Customizing a Hugo theme

The Etch theme is great, but I found a few ways to customize it so that it better meets my needs.

Rather than editing the theme’s files directly, it’s important to override them. I copied <project root>/themes/etch/assets/css/dark.css to <project root>/assets/css/dark.css and edited the new file.

embedded gists

Etch’s dark mode doesn’t do anything for embedded gists, making them blindingly bright when Dark Reader is disabled.

blinding gist embed

Eventually I found Customizing GitHub Gists. After some experimentation, I was satisfied with this result:

custom gist CSS demo

Here’s the CSS:

body .gist .gist-file,
body .gist .gist-data,
body .gist .highlight {
    background: #2e2e2e;
    border: none;
}

body .gist .blob-num {
    color: #f5f5f5;
    background-color: #3e3e3e;
    pointer-events: none;
}

body .gist .gist-meta {
    display: none;
}

body .gist .blob-code {
    font-size: 14px;
    filter: contrast(5%) brightness(140%) saturate(5000%);
}

background color

Dark Reader was putting a box around each page’s content. This change made the box mostly invisible.

body {
    color: #ebebeb;
-    background: #121212;
+    background: #1e1e1e;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

text color

The bright text on the dark background was a little painful to read, so I made the text a little darker. The left half of the image below is the original color, and the right half is the new color.

text-color-change.png

I also made links slightly darker.

Here are the changes:

body {
-    color: #ebebeb;
+    color: #c4c9ce;
    background: #1e1e1e;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

header#banner a {
-    color: #e0e0e0;
+    color: #c4c9ce;
    text-decoration: none;
}

header#banner nav ul li a {
-    color: #cccccc;
+    color: #c4c9ce;
}

main#content a {
-    color: #00b1ed;
+    color: #20acdb;
}

main#content p {
-    color: #f5f5f5;
+    color: #c4c9ce;
}

code block background color and border radius

The default appearance of multiline code blocks looked good, but inline code blocks had the same background color as the rest of the site; sometimes it was difficult to tell where inline code blocks started and ended. I made the background color of both types of code blocks brighter to fix this.

div.highlight pre,
code {
    background-color: #38383d;
    border-radius: 6px;
}

I also added a tiny border radius to images.

img {
    border-radius: 6px;
}

latest edit date

I thought I was going to have to customize the template to show the latest edit dates of pages, but it already supports this with a lastmod variable in the frontmatter. If the values of date and lastmod are the same, lastmod is ignored.

title = 'Customizing a Hugo theme'
date = 2024-01-15T15:47:01-08:00
lastmod = 2024-01-16T15:47:01-08:00

tables

By default, tables in Etch have no borders. That can make tables hard to read, so I added some simple borders that aren’t too distracting.

table,
th,
td {
    border: 1px solid #424141;
    width: 100%;
    border-collapse: collapse;
    padding: 0.5rem;
    text-align: left;
}

However, Etch also uses tables for some code blocks. The CSS above adds a bunch of borders that make those code blocks look worse:

code-block-line-number-borders.png

This is fixed by adding a litte more CSS:

td.js-line-number {
    border: none;
}

redirecting

Some of my notes here have improved enough over time that they feel blog-worthy, so I would like to move them to my blog. I don’t want to break links to pages here though, so I looked into how to redirect to other pages.

Hugo has something called aliases for redirecting, but it only works between pages on the same domain. I want to redirect from a subdomain to a root domain, so I can’t use aliases for this.

HTML allows a few ways to redirect to a new page. Here’s the way recommended on Meta refresh - Wikipedia:

<body onload="window.location = 'http://example.com/'">
</body>

There’s also this way that can apparently make the browser’s back button get messed up:

<head>
	<meta http-equiv="refresh" content="0; URL='http://example.com/'" />
</head>

Neither of these can be put directly into a post on a Hugo site since the <head> and <body> elements are outside of the post’s scope.

To solve this, I found the file in my theme with the <body> tag and changed it to this:

<body {{- with .Params.redirect }} onload="window.location = '{{ . }}'"{{ end }}>

Now, I can make a post redirect anywhere by just adding a line like this to the post’s front matter:

redirect = 'http://example.com/'

For those with JavaScript disabled, I also added a redirect link a few lines below the body tag:

{{- with .Params.redirect -}}<br><a href="{{ . }}">Click here to redirect.</a>{{- end -}}

allowing HTML in posts

By default, Hugo does not allow HTML to be added to markdown files without converting it from HTML for security reasons. If you do want to use HTML in a post without having Hugo render it, you have two options: create a custom shortcode or turn off all HTML rendering.

create a custom shortcode

In your layouts/shortcodes folder, create a file named safeHtml.html with content {{- .Inner -}}. Then you can use this custom shortcode in a markdown file like this: {{< safeHtml >}}<h2>hello</h2>{{< /safeHtml >}}.

Here’s more about shortcodes:

turn off all HTML rendering

In your Hugo configuration file, add the setting below.

If you use hugo.toml:

[markup.goldmark.renderer]
  # Allows HTML in markdown
  unsafe = true

If you use hugo.yaml:

markup:
  goldmark:
    renderer:
      # Allows HTML in markdown
      unsafe: true