Using Hugo to build this site
This is just me organizing my thoughts and saving them for the future. I’m positive there are many ways to optimize this project…but sometimes getting the job more or less done is enough.
Requirements
I really wanted something small and simple first and foremost. Pure .html would have been perfect, but I needed the same (or at least similar) header or footer on every page. If only html had some sort of include tag…
Using PHP I could have includes, however it also requires setting up a development environment on my machine. Running and configuring a server etc. These are not huge obstacles, but I’m only going to do all this for one website so the less overhead the better.
Why not Wordpress?
I did run this site on Wordpress for quite a while, however it was just So. Much. Overkill. for what is essentially a static site. I had to update it periodically. There were exploits and vulnerabilities, plugins would lose support and become outdated. It was a mess.
So why Hugo?
Minimal footprint on my system - a single .exe and PATH variable entry. There’s a bit of a learning curve, but I only need probably like 10% or less of its functionality for everything I have planned. It allows me to use templates, partials, write entries in Markdown and generates a nice light static site. Presentation and content are completely separate, so that’s great for longevity, in case I ever need to change the look.
Ease of use and minimal footprint for the cost of a few days of trial and error. Neat!
Later I also realized that the Hugo server automatically refreshes my page whenever I make a change to any file, which makes editing and checking changes a breeze.
Getting Started
Three simple steps to begin your Hugo journey:
- Download Hugo from GitHub and store it somewhere safe.
- Add it to my PATH variable in windows
- Test by typing “hugo version” into the console
Building a site
Site and a theme can be generated with two brief console commands:
hugo new site ravenmore
hugo new theme ravenmore
…though probably I could have skipped the theme part? Anyways, that’s how I did it and all presentation parts are defined in the theme. I still suspect for such a simple project defining all the base templates partials etc. in the original project folder would have worked just as well. Oh well, moving on…
Converting the site to a theme
I already had a static html template I used as the base of my Wordpress theme. My plan was to convert it to…whatever it is that Hugo needs (I did not know at this point) by moving it piece by piece. I needed to figure out super basic stuff first: where to put and how to access my CSS and JS files. From online guides I gathered that the static folder is the way to go in case of simple projects. I can access it easily by typing an absolute path, like:
<script src="/js/myjs.js">"
This links to “myhugofolder/static/js/myjs.js” which is good enough for me.
With JS/CSS ready for access, I moved the contents of my index.html to myhugofolder/_default/baseof.html. This is where the magic happens. Thanks to Hugo I can replace the dynamic part of my .html that changes between pages with a block:
{{ block "footer" . }}
{{ end }}
This allows each template to define what exactly the “footer” block means, for example:
{{ define "footer" }}
{{ partial "introduction.html" . }}
{{ partial "footer.html" . }}
{{ end }}
Adding the gallery
In _default/gallery.html I define what “main” means in the context of the Gallery page.
{{ define "main" }}
<div class="content_container">
<div id="gallery" >
(...images go here...)
</div>
</div>
{{ end }}
{{ define "footer"}}
((footer html goes here))
{{end}}
{{ define "javascript" }}
{{partial "javascript_footer_default.html"}}
{{ end }}
Each page can have essentially three different elements: different content (duh), different footers, depending on where we are, and different javascript to support the content. This is reflected in my three blocks aptly named main, footer and javascript.
Lastly I create content/gallery/_index.md which contains these few lines:
+++
template = 'gallery.html'
+++
This is what Hugo calls “head matter” (not to be confused with brain matter) This line tells Hugo to use my gallery.html template to display whenever /gallery/ is called in the url.
So far so good!
Adding proper content
OK, last but not least I need a list of projects for the section you’re browsing right now and a way to display each individual project. By default Hugo uses these two templates to accomplish the task:
_default
└ single.html
└ list.html
This is where Hugo really starts to shine. You see, content is stored as markdown files. In list.html we can loop through these files and sort, filter, group and display them in different ways depending on their head matter. I only have a very simple use case for this, which is grouping projects based on their thumbnail head matter entry. If they have a thumbnail it’s a major project and goes first on the list. If it’s a minor project it will not have a thumbnail entry, use a different css class and be displayed after all the main projects.
{{ range .Pages }}
{{ if .Params.image }}
<div class="project_link">
{{ with .Params.image }}<img src="{{ . }}">{{ end }}
<h2>{{ .LinkTitle }}</h2>
<a href="{{ .Permalink }}"><span></span></a>
<p>{{ .Summary }}</p>
</div><!-- project_link -->
{{ end }}
{{ end }}
Including screenshots
So apparently again the /static folder comes to my rescue. I just store them in their own folder and reference with Markdown, kind of like this:
![ImageAltText](/projects/hugo_exampleImage.jpg)
Extras - code highlighting
I used pure CSS code blocks with a single color (a fancy yellow, I might add), but it looked really, really dull. So I found a popular code highlight solution - HighlightJS.
Usage was as simple as including a single javascript file and a css file. Only problem I ran into was that the default CSS was intended for use on a light background. After some more googling I helped myself to the Dracula Theme for highlight.js and this part was done.
Or was it? Unfortunately I ran into an issue where the gallery javascript could conflict with highlight.js. The solution was to not call them together, I really do not have a use case for that anyway. So I changed the partial from baseof.html
{{ partial "javascript.html" . }}
To a block:
</body>
{{ block "javascript" . }}
{{ end }}
</html>
Allowing each template to define the javascript partial being used. I created two partials, one for the gallery pages, one for projects including code.
And that’s all there is to it, that’s all this page has under the hood.
Deployment
Once everything is set up it’s enough to run the hugo command in console:
hugo
a new “public” folder will be created.
Extra - adding a new content type
This happened when I wanted to extend the default gallery, which was just an image slideshow, into a list of links to sub-pages, like the Projects section.
Step 1: Creating a New Content Type
It’s enough to create a new folder inside ‘content’ and put _index.md there
content/
└──contenttype_new/
└──_index.md
Note: without index.md it will work! Hugo will use the default to list.html to display content.
Step 2: Displaying the new content
Essentially I want a list kind of page that behaves like the gallery used to (so a square grid of images). To create a custom list for your content type you need to create a list.html inside the “contenttype” folder of your layouts directory (it can be in your theme or in the main Hugo folder).
themes/
└──mytheme/
└──layouts/
└──gallery/
└──list.html/
My list.html code:
{{ define "main" }}
<div class="content_container">
<div id="adom" class="gallery">
{{ range .Pages }}
<a href="{{ .Permalink }}">
<div class="image">
<img src="/gallery/thumbs/{{ .Params.image }}" />s
</div><!-- image-->
</a>
{{ end }}
</div> <!-- gallery -->
</div> <!-- content_container -->
{{ end }}
{{ define "footer" }}
{{ end }}
Note on using Params
Each pages head matter has an option to include params like so:
+++
[params]
image = 'adom.jpg'
+++
You can then recall params using
{{ .Params.image}}
Conclusion
I really love this setup now that it’s done. It’s really easy to write my thoughts in Markdown and upload a new version of the site with fresh entries.
Creating and configuring everything in Hugo was a bit of a hassle, but a large part of that is on me. If I was going for a simple blog and used one of the many existing themes everything could be done from scratch in one afternoon, including learning and reading the docs.
If I ever decide to change the layout (and I really, really hope I don’t), all my content is stored separately from the presentation layer. It’s just a matter of redefining the partials, blocks and CSS.