Overview
After many years of thinking about it, I finally decided to sit down and fire up a blog. After some slight decision paralysis I elected to use Hugo as my blog engine of choice.
When I stumbled upon the aafu theme I found that it was almost exactly what I wanted: somewhere I could host my bio, resume, and a blog. My resume has already been hosted in a docker image based on read the docs, but I was never fully satisfied with it.
Forking the Theme
My fork of aafu extends the base theme in several ways:
- It uses a more modern FontAwesome library loaded off of the Cloudflare CDN
- Adds a software/application section to the portfolio to detail applications I am familiar with
- Adds a Table of Contents that remains visible as well as reacts to which section you are in
New FontAwesome
This was a simple patch:
--- a/layouts/partials/head.html
+++ b/layouts/partials/head.html
@@ -1,10 +1,11 @@
<head>
{{ partial "meta" . }}
<link
- rel="stylesheet"
- href="https://use.fontawesome.com/releases/v5.15.2/css/all.css"
- integrity="sha384-vSIIfh2YWi9wW0r9iZe7RJPrKwp6bG+s9QZMoITbCckVJqGCCRhc+ccxNcdpHuYu"
- crossorigin="anonymous"
+ rel="stylesheet"
+ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css"
+ integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A=="
+ crossorigin="anonymous"
+ referrerpolicy="no-referrer"
/>
<link
rel="stylesheet"
Software Section
This was fairly straightforward.
All that needed to happen was to copy layouts/partials/accordion/skill.html and find/replace skill with software.
<script>
let softwarePanel = document.querySelector("#software-panel")
.previousElementSibling;
softwarePanel.addEventListener("click", function() {
let softwareBars = document.querySelectorAll("#software-percent");
softwareBars.forEach(elem => {
elem.style.width = elem.classList[0];
});
});
</script>
{{ range.Site.Params.software.list }}
<code>{{ .software }}</code>
<div class="w-100 mt-1 mb-3 border border-black dark:border-gray-300 rounded-sm" style="height: 1.25rem;">
<div id="software-percent" class="{{ .softwarerating }}% bg-blue-500 dark:bg-yellow-700 h-full rounded-sm" style="width: 0; transition: all 0.5s;"></div>
</div>
{{ end }}
This allowed me to add an additional section to my config.yaml file:
showInAccordion:
- item: aboutme
expand: true
- item: experience
- item: education
- item: project
- item: skill
- item: software
- item: hobby
---
skill:
title: Skills
panelId: skill-panel
icon: fas fa-cogs
list:
- skill: "LDAP"
skillrating: 90
- skill: "Perl"
skillrating: 75
- skill: "E-discovery/Evidence Collection"
skillrating: 80
- skill: "GRC"
skillrating: 60
software:
title: Software and Services
panelId: software-panel
icon: fab fa-linux
list:
- software: "OpenLDAP / Slapd"
softwarerating: 90
- software: "HAProxy"
softwarerating: 75
- software: "Eramba"
softwarerating: 50
- software: "Snipe-IT"
softwarerating: 70
- software: "MySQL"
softwarerating: 75
Adding a ToC
I prefer to have a linked table of contents in every article I write for work - I feel it helps users skip directly to what they are looking for and save time. Fortunately Hugo makes implementing theme changes very easy once you code them.
Adding the ToC to generated blog posts was fairly straightforward: simply modify the single.html layout to include the ToC data Hugo automatically generates:
<div class="article-layout">
<aside class="toc">
<h2>Contents</h2>
{{ with .TableOfContents }}
{{ . }}
{{ end }}
</aside>
This also necessitated adding a custom.css file to contain the formatting for the table of contents.
Automatic scrolling required loading a simple scrollspy.js script who’s formatting was also controlled via custom.css.
The original aafu theme does not support loading custom.css by default, so layout/partials/head.html needed to be modified:
--- a/layouts/partials/head.html
+++ b/layouts/partials/head.html
@@ -15,6 +16,7 @@
href="//fonts.googleapis.com/css?family=Didact+Gothic%7CRoboto:400%7CRoboto+Mono"
/>
+ <!-- Main CSS -->
{{ $css := resources.Get "main.css" | css.TailwindCSS }}
{{ if hugo.IsProduction }}
{{ with $css | minify | fingerprint }}
@@ -25,12 +27,29 @@
crossorigin="anonymous"
/>
{{ end }}
-{{ else}}
+ {{ else}}
<link href="{{ $css.RelPermalink }}" rel="stylesheet" />
-{{ end }}
+ {{ end }}
<link href="{{ $css.RelPermalink }}" rel="stylesheet" />
+ <!-- Static Styles -->
<link rel="stylesheet" href="{{ `/css/general.css` | relURL }}" />
<link rel="stylesheet" href="{{ `/css/search.css` | relURL }}" />
+ <!-- Custom Style-->
+ {{ $custom := resources.Get "custom.css" | minify | fingerprint }}
+ <link
+ rel="stylesheet"
+ href="{{ $custom.RelPermalink }}"
+ integrity="{{ $custom.Data.Integrity }}"
+ crossorigin="anonymous"
+ />
+
+ <!-- Scrollspy -->
+ {{ $spy := resources.Get "scrollspy.js" | minify | fingerprint }}
+ <script
+ src="{{ $spy.RelPermalink }}"
+ integrity="{{ $spy.Data.Integrity }}"
+ crossorigin="anonymous">
+ </script>
<script>
let html = document.querySelector("html");
While I was editing the file I also added a few comments and fixed some indentations to keep file hygiene up.
###Cloning the Theme into my Blog Since I elected to modify an existing theme and run with it, it made sense to clone the theme instead of simply copy the files. This also allows me to manage my aafu repository from its working directory inside of my hugo repo, allowing me to develop easily. The one caveat to this was that, because they are two separate and unique projects, I wanted to utilize the aafu repo as a submodule.
git submodule add git@github.com:andrewmeyer/aafu.git hugo/themes/aafu
Docker Builds
Now that I had the blog’s skeleton and theme configured, it was time to fire up my first staging build on my workstation. The dockerfile was fairly straightforward to implement and I later extended it with the ability to select stage and production build environments:
# Stage 1: Build Hugo site with Tailwind and Pagefind
FROM hugomods/hugo:debian-node-lts-non-root AS builder
WORKDIR /src
# Copy your Hugo site into the container
COPY hugo/ /src/
#select build environment
ARG BUILD_BRANCH=master
ENV BUILD_BRANCH=$BUILD_BRANCH
RUN echo "using $BUILD_BRANCH as the build branch"
# Install Node dependencies for Tailwind etc.
RUN npm install
# Build Hugo site
RUN if [ "$BUILD_BRANCH" != "master" ]; then \
hugo --environment stage --minify --buildDrafts --buildFuture; \
else \
hugo --environment production --minify; \
fi
# Run Pagefind indexing on the generated site
RUN npx -y pagefind --site public
# Stage 2: Serve with Nginx
FROM nginx:alpine
# Remove default nginx static content
RUN rm -rf /usr/share/nginx/html/*
# Copy the static site (now with pagefind assets) into Nginx root
COPY --from=builder /src/public /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
This Dockerfile also alleviated one of my big pet peeves about containers: simply dumping the entire repository into the container environment and hoping nobody notices. Now Hugo will ignore draft articles by default when building, but include them for viewing in a staging environment.
Conclusion
And with that I was able to launch my blog on localhost:80 and begin poking around! I imagine that this dockerfile will be scaled down when some of the build steps are taken over by Gitea actions.