Hugo

Admonish the Callout

Alert triangle with an exclamation icon

Micro.blog has recently enabled Hugo v0.158.0 for usage. The last version available to users was v0.117.0 and v0.140.0. And as Jason has pointed out on his blog, there are some big changes.

One of the changes of note was the inclusion of render hooks for callouts included in v0.132.0. This is coupled with the enhancements in v0.134 makes it more compatible with GitHub, Obsidian, and Typora.

The whole goal of this is to have markdown text like the following

> [!NOTE]
> Useful information that users should know, even when skimming content.

generate HTML and have the browser render into the following example

In case there is an error with processing the markdown, I’ve placed a static version of the HTML in this document below.

I wanted to implement this because I sometimes play around with Obsidian and I really enjoy OtΓ‘vio’s plugin to publish to Micro.blog. With this, I can have the website follow the behavior of reading mode in Obsidian. I started writing this post in December of 2024. I ran into some issues along the way, but I kept coming back to this. At this point, some of the references are no longer available. My desire for writing in a way where I would use this functionality is no longer there.

But, it’s cool, and I know that there might be someone out there who can use this.

I set up a gallery of examples using the list of callouts from the Obsidian Callout Manager. You can look at the text used to make the examples to see if this is something that you want to incorporate into your writing.

I’ve tagged this particular release on GitHub so you can see exactly what I’m using at the time of this writing.

If you have any questions or suggestions, feel free to email me.

Resources

I’m leaning heavily on the resources that I’ve found on the internet. I want to take a moment to recognize their work and others can get it directly from the source.

Nicholas Martignoni’s Hugo Notice
This is a plugin that I saw a while ago and was thinking about putting into my theme before the official release of render hooks.
Liu Jinyi
This is where I got the final design for the admonitions from. I decided to make some changes so that it matches the style that I wanted to go for. At beginning of this project, the build system I was using did not allows for sass.

Creating the callout

HTML structure of the callout where an aside element contains two nested elements; a header and a div. The header contains a svg and h3 tag.
Diagrams help me think of the overall structure as a combination of different blocks.

When it comes to designing, I like to take inspiration from what is already available. I spent a lot of time goofing off researching how other people have implemented this and tried static version of those in my theme to see what I liked and didn’t like. Sometimes this takes up a lot of time as I try to understand why the original authors make certain decisions. Is it a technical or design choice that makes someone use <blockquote> or <div> for the final product?

This article about pullquotes better articulates why I use <aside> instead of <blockquote>. I have seen people use <figure>, but choose not to because I feel that figures are an essential part of the document while <aside> is additive.

I also went with a <header> inside of the admonition in the hopes that I’ll better understand how the different pieces come together. In addition, I used the <h3> tag to meet up with the heading convention that I’ve been using. I see the callouts as section of the document that contains information

I placed the content in a <div> for logistics and styling.

Iconic Icons

For the <svg>, I took some time to understand how they work in HTML and Hugo. I was already in the process of adding SVG icons to the site to make it stand out more. SVG stands for Scalable Vector Graphics. They are text representation of a graphic that we can embed within the document for the browser to render.

These are some that popular sites where you can get SVGs.

tabler icons
When I started looking into adding icons, this was one of the first links that came into my search.
font awesome
This is where Roneo got his icons. It’s a great option that is used in a lot projects on the internet.
Simple Icons
Another good set of icons.
Lucide
These are the icons that GitHub uses.
Iconify Design
This is a nice directory of icons that show you a small preview of the style icon libraries.

If you use any of these options, I want to encourage you to make a donation so that they can continue with the cool stuff that they are providing.

I went with the tabler icons, because I felt that the rounder style matches the ascetic that I’m going for when I started the site.

I’m in the process of implementing icons within my markdown after reading an article about SVG imbeds1 but that’s for a future post.

If you are into reading more about SVGs, there is a free book on SVG that I’m thinking about adding to the list.

Static Structure

The resulting static HTML that I created to do my color styling looks similar to the following.

<aside class="admonition note">
  <header class="admonition-header">
  <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="icon icon-tabler icons-tabler-outline icon-tabler-note">
    <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
    <path d="M13 20l7 -7" />
    <path d="M13 20v-6a1 1 0 0 1 1 -1h6v-7a2 2 0 0 0 -2 -2h-12a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h7" />
  </svg>
  <h3>Note</h3>
  </header>

  <div class="admonition-content">
    Useful information that users should know, even when skimming content.
  </div>
</aside>

Styles and colors

For the initial implementation, I wanted to get the 5 states defined in the GitHub documentation which are note, tip, important, warning, and caution. This took longer than it should because I was having trouble deciding on what icon I should use for note and important because of the different samples I was pulling from contradict.

I placed static copies of the HTML in a page with the first line changed to the corresponding type as the class.

For example, the class for tip would look like this:

<aside class="admonition tip">

I then created a separate CSS file and linked it in the site header. I’m hoping that it will make things easier to find and modify styles in the future2. Since I’m working from Jinyi’s code as my base, I start off with the basic admonition and a note.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
:root {
  --admonition-color: var(--accent, #5e81ac);
}

.admonition {
  margin: 1em;
  padding-left: 0;
  
  border: 2px solid var(--admonition-color);
  border-left: 6px solid var(--admonition-color);
  border-right: 3px solid var(--admonition-color);
  border-radius: var(--border-radius, 1em);
  
  box-shadow: 0 2px 4px var(--admonition-color);
}
Line 2
I define the default color for the admonitions to be the accent color of my site with a default value in case someone takes this file and attempts to use it by itself.
Line 9-12
I use the --admonition-color to set the borders appropriately.
Line 14
I use a box-shadow to give the callout some depth.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
.admonition-header {
  padding: 0.5rem;
  display: flex;
  align-items: stretch;
  
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 0 var(--border-radius, 10px) 0 0;
  color: var(--admonition-color);
  background: 
    color-mix(in srgb, currentColor, transparent 75%);
  
  svg {
    width: 1.1em;
    height: 1.1em;
    margin-right: 0.5rem;
  }

  h3 {
    color: var(--text);
    font-size: large;
  }
}
Line 7
Defines the upper right hand corner to be rounded to fit within the containing admonition. I attempted to use inherit but it wasn’t working.
Line 8
This is where the magic happens and we start seeing the Cascade portion of CSS. This makes the forefront/currentColor --admonition-color. This is used in fonts and any svgs that are in the header.
Line 10
I didn’t want to define two colors and found this tip on stack overflow to do a transparency translation of it.
Line 19-20
These are there to make some adjustments for contrast and size.

After that, I add a little bit of styling for the contents.

.admonition-content {
  padding: 0.5rem;
}

After that, we look at our base example.

Admonition undefined in lightmode.

Here it is without the rendering.

With this, I can change the color based off the alert.

.admonition.note {
  --admonition-color: #096ae1;
}

If I want to have the same color for multiple alerts, I can add an extra line for it.

.admonition.danger,
.admonition.warning {
  --admonition-color: orangered;
}

Implementing the Render Hook

I started with the example from the blockquote/alert documentation and I was really happy to know that it worked correctly by simply creating the file and putting the sample code in. Making the changes to the HTML tags was also pretty straight forward.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{{- $icons := dict
  "caution"     "alert-triangle.svg"
  "idea"        "bulb.svg"
  "important"   "info-circle.svg"
  "info"        "info-circle.svg"
  "note"        "note.svg"
  "tip"         "bulb.svg"
  "warning"     "exclamation-circle.svg"
}}


{{- if eq .Type "alert" }}
{{- /* Render admonition. */}}
{{- $type := cond (index $icons .AlertType) .AlertType "info" }}
{{- $iconFile := printf "admonitions/icons/%s" (index $icons $type) -}}

<aside class="admonition {{ .AlertType }}">
  <header class="admonition-header">
    {{ if templates.Exists (printf "partials/%s" $iconFile) }}
    {{- partialCached $iconFile . }}
    {{- end }}
    {{- with .AlertTitle }}
    <h3>{{ . }}</h3>
    {{- else }}
    <h3>{{ or (i18n .AlertType) (title .AlertType) }}</h3>
    {{- end }}
  </header>
  {{- with .Text }}
  <div class="admonition-content">
    {{ . }}
  </div>
  {{- end }}
</aside>

{{ else }}
<blockquote>
  {{ .Text }}
</blockquote>
{{ end }}
Line 1-9
Create a dictionary to match which image goes to a specific image. Jinyi used the icon set from font-awesome so the names are not an exact match. I started off with just the basics and add info because I was working on this late at night and couldn’t remember if it was info or important that was part of the five initial alerts.
Line 12
The render hook will parse the different blocks of text and will set a flag on whether this block is an alert or not.
Line 14
Look in the dictionary for the alert type that was given by the user. If the alert type isn’t there, it will use info as the default. I decided that if I don’t have an icon in mind, I want it to show up as information to be given to the user.
Line 15
This specifies the path to the SVG that we’re going to use. I had attempted to use the method from Ronoe to load image from the assert directory but I didn’t understand the code at this point in time. I used a different variable for the file name because I didn’t want to confuse myself later on.
Line 17
Specify the alert type in the class list for the admonition to use the proper styling.
Line 19-20
Hugo loads the contents of the partial if it exist and puts it in the output. It’s a safe guard in case I add an image to the icons dictionary but don’t upload the file. In addition, there was a change to the templating system introduced in v0.146.0 that renamed partial to _partial. Be aware of that when implementing this on your own.
Line 22
Check if there is an alert title and place it in the heading on the following line.
Line 25
If the title isn’t there, we use the alert type for the heading. All the examples that I’ve seen also include the step of sending it through i18n for internationalization. One thing I noticed, is that it capitalized the alert properly before I created the associated translation file. I might just leave it that way because I’m currently the only one using this theme.
Line 28
This checks for the content of the alert and places it in a <div> for the admonition.
Line 35
If there isn’t an alert, text is processed as if it was a normal <blockquote> element.

Further callout options

After the initial creation of the render hook, I took some time away from the project. Some of the people that create content that I enjoy use Obsidian on a regular basis for writing and the ever growing list of what that application can do. Someone pointed out that there is a Callout Manager and the default has more than the list that I originally created. Other tools also have a wider assortment. I added a couple more to the dictionary, but I noticed that this would get tedious to add keys that would go to the same value. For example, in my list info and important use the same image.

So, after a little bit of trial and error, I was able to put together the following code block

1
2
3
4
5
6
{{- /* Define a list of keys that should share the same icon */ -}}
{{ $keys := slice "important" "warning" "error" }}
{{- range $keys }}
  {{- /* Merge each key into the dictionary with the same icon value */ -}}
  {{- $icons = merge $icons (dict . "exclamation-circle.svg") }}
{{- end }}
Line 2
Place the keys that I want to have the same image
Line 3
Tells go to loop through all the keys that are defined
Line 5
Creates a small dictionary with the key and the name of the image. Then it merges that dictionary with the icon dictionary and saves it.

I’m still a beginner at the go programming language and I don’t know if this is saving by value or reference. I also don’t know if this is more performant than having a longer dictionary with all the values. I’m hoping that the comments and this article helps me remember this the next time I want to add something.

Making it a little more accessible

During this development process, I noticed that one example would load the SVG and add aria-hidden="true" to make screen readers skip over the image without alternative text. I edited the SVG files that I use to have this additional line and played with the idea of adding aria-labelledby but I don’t have a way of reliably setting it and don’t know how this would improve the user experience.

The same example, also set the title, but I didn’t use this as this images are purely decorative. You can read this article about knowing the different use cases for aria visibility.

What’s the next step?

I feel the next step that I would like to pursue is to get get the colors to work better in the dark mode of my theme. I don’t feel that the contrast is good enough for warning and I’m thinking about moving to CSS colors such as blue or rebeccapurple instead of hexidecimal values. I’ve already done one like the following

.admonition.important {
  --admonition-color: light-dark(rebeccapurple, mediumorchid);
}

I’d also like to adjust the alignment of the icons. I don’t know if this is because I took the examples from different icons that are sized differently or if having the icon outside of the <h3> is causing more issues than it’s worth.

As always, I appreciate any feed back and I hope this article finds you well.


  1. By the time I got ready to publish this article, the site was no longer available. I’m hoping that it’s just a temporary shutdown until this person has the domain refreshed. ↩︎

  2. I have had to stop myself a couple times from trying to find the best way to deliver the HTML/CSS for this feature. Should I have separate files with style rules that I might not use or put it inline and worry that I might have an article that use dozens of these things? I feel shipping is more important. ↩︎

Restarting Theme Development

This post is a bit of a ramble and more for documenting my thinking.

Things have been kind of hectic in my personal life and I’ve been taking a step away from creating and interacting. In the time that I’ve been away, there have been changes to Hugo and the Micro.blog. In some ways, it’s been a relief that Micro.blog is using v0.117. Other than the changes in v0.132 (The introduction of alerts although v0.140 and v0.142 has some significant fixes to this), I haven’t really seen anything catches my interest.

Still, I have seen some interesting things being done with blogs and want to be able to take advantage of the newer versions of Hugo when Manton and crew make it available.

I thought I would document what steps I went through. I’ve begun writing this on September 24th and worked on it in my spare time until clicking the publish button.

Environmental Setup

At the beginning of this process, I had Hugo v0.146.3 installed on my MacBook Air running Tahoe 26.1. I want to be able to test in different versions of Hugo so did a search and found several article pointing to hvm (Hugo Version Manager). The tool was created by Joe Mooring who is very active on the Hugo Forums and you can go to the GitHub repository to review the code.

The first thing I did was use Kostas’ instructions for using brew to get a certain version of running a specific version of Hugo and then I downloaded the v.117 hugo ruby installer.

That didn’t work.

So, I downloaded the homebrew-core from the GitHub repository and then changing to the commit that has the version I want.

git checkout e243fd4

That didn’t work for me as well and I grew tired of trying to find the right combinations of brew commands.

So, I followed the directions and ran the next step to see an error

mandaris@skylite ~ % hvm gen alias --help
zsh: command not found: hvm

That’s when I realized that my system is almost a clean install other than the installation of the command line tools and brew, I didn’t have things like /usr/local/bin or anything else that I had taken from granted in my previous setup.

I set up oh-my-zsh and kept the defaults. I forgot why I use this but not how. I added the following to my .zshrc

export PATH=$PATH:$(go env GOPATH)/bin

Then new shell instances will be able to find the executables from GO.

➜  ~ which hvm
/Users/mandaris/go/bin/hvm

When I ran it the first time, I didn’t see my option and asked on the forums before I went through the associated documents to see that I could add the specific version to a .hvm file that I can put in the root of the folder I’m working with.

➜  local-hugo hvm status
The current directory is configured to use Hugo v0.117.0.
Cached versions of the Hugo executable:

v0.151.0
v0.117.0

Now I’m able to switch between the versions easily.

The only problem is that some of the plugins that I use locally are not compatible with that version. For example, the stoot plugin to embed mastodon post.

Hashtag Goals

Other than the work to keep the theme ready for newer versions of Hugo, I’ve identified a couple other things that I want to work on.

  1. Increase the performance of the site
    I don’t want to remove styling or minimize the file because I feel that it will help others learn and I’m too afraid to kill my darlings.
  2. Move the About me to the bottom
    I feel having it on the side on larger screens draws focus away from the writing on page.

In addition, I have to figure out why @view-transition doesn’t work on the server but works on my local copy of the site.

The goal is to get this all finished before Thanksgiving break. So if you’re reading this please feel free to bug me about it as my self imposed deadline draws near.

Take Care!

I'm tired boss... upcoming deprecations

I've been working on an update for my website theme to scratch a technical curiosity I was feeling related to authorship of individual posts in comparison to the entire site. After reading a couple resources, I decided to ask on the Hugo forums if there was an ideal way to add author information. I kept running into an issues and figured that it might be related to the version change.

Hugo deprecation warning
Warnings are future errors. A technical debt for waiting to come due.

Here are the warning messages if you want to read over them.

WARN  The "gist" shortcode was deprecated in v0.143.0 and will be removed in a future release. See https://gohugo.io/shortcodes/gist for instructions to create a replacement.
WARN  The "twitter", "tweet", and "twitter_simple" shortcodes were deprecated in v0.142.0 and will be removed in a future release. Please use the "x" shortcode instead

I have flashbacks of when I was working with another static site generator called Pelican that I enjoyed for many years until one day I did an update1 that took the site down because I had to find fixes for all the different components that weren’t working anymore.

On some levels, I understand that I don’t need to upgrade and that’s part of why I’m on my current hosting provider. The point of my blog is to communicate with the World Wide Web, get my thoughts together, and fulfill that part of me that likes to create. I feel that some of the things that I create for this blog are only used during the creation and never utilized afterwards.

What’s frustrating about these warnings are they are related to shortcodes built into Hugo itself. They are part of the documentation and examples that Hugo has to showcase what the project can do. I feel that it’s a real help when writing an article to avoid pasting the larger and larger code blocks used to embed something into a post. But with the changing technical and political landscapes, I can see why these changes are coming.

I’m sad.

Further bitrot.

I’ve already removed most if not all of the twitter links on my site and based on the last time I checked traffic, no one was reading it anyway. The gist changes are a little sadder for me because I was using them as reference in some of my favorite posts and I feel that people still read those.

But, I’m not updating the version today

The current version on the server is 0.117 and that’s been really solid. There is a version .140 that’s available but I wasn’t able to get it working.

Problem for stoot

I was able to take a code sample from Bryce last year and make it a plugin for Micro.blog users and I named it stoot after the shortcode that Bryce used for it. Unfortunately, it’s now giving me an error in my local environment.

The following is a truncated snippet of the error.

ERROR render of "/" failed: failed to render shortcode "stoot": failed to process shortcode: "/Users/mandaris/Code/local-hugo/themes/stoot/layouts/shortcodes/stoot.html:13:28": execute of template failed: template: _shortcodes/stoot.html:13:28: executing "_shortcodes/stoot.html" at <$urlToGet>: can't evaluate field Err in type resource.Resource
---
toot.html:13:28: executing "_shortcodes/stoot.html" at <$urlToGet>: can't evaluate field Err in type resource.Resource: Resource.Err was removed in Hugo v0.141.0 and replaced with a new try keyword, see https://gohugo.io/functions/go-template/try/

And yes, it did say toot.html even though it was from stoot.html. One problem at a time!!

The code in question:

{{- with resources.GetRemote $urlToGet  -}}
	{{ if (resources.GetRemote $urlToGet).Err }}

Next action(s)

I’ve decided that my next actions will be the following.

  1. Ignore the gist issue. It’s marked for a future release and there are directions on how to replace it. I have a about a handful of examples in my test suite of content (mostly the same code but on different pages)
  2. Learn how to keep multiple copies of Hugo local so that I can test this kind of thing easier.
  3. Learn how get replacement to work according to the error message.

  1. I took it for granted that a project would just work better after and upgrade; all reward and no consequences. You should not only backup your content but the environment. Look at how much work people maintain game emulators do in order to keep their backups running. ↩︎