Skip to main content

Labarum

It's the little things in different browsers

Boxes in front of checkboxes
Labarum: Extra content in items
I hate it when a developer focuses so much on one browser (usually chrome) and doesn't test it in another browser. So, I feel like a hypocrit when I found out that my site renders the little box in front of the checkboxes[^checkboxes]. The funny thing is that I had originally seen this as an issue and had commented the code out.

The I thought I would keep it as a comment until I could figure it out and deploy it as a point update.

article ul > li::marker {
	/* content: "\2751"; */
}

The problem is that chrome doesn’t care that I had the individual line commented out and was attempting to put it there even though I told it not too.

I moved the comment to outside the item and I’ll let the broswer handle markers until I get a better understanding of how to target the different items.

Creating Labarum (Part 6): A Splash of Color

Labarum part6 light mode

I’m wrapping up this series. I’ve been playing with this theme for more than a year. Rarely consistent and not always forward progress but rewarding. I’m at a point where I’m very happy with how the theme looks.

This is what it looks like in dark mode.

Labarum part6 dark mode

Colo(u)rs

I wanted to use the Nord color scheme at the beginning of this project, but decided to use “basic” colors to simplify the design. I eventually grew to love the look of the page as the content was the star.

Later I found that some of the elements on the page don’t work well for those who are color blind and the starkness of having an all white background made me rethink whether the site would do well with long pieces.

I first came across the Nord color palette when I met Jessica Smith online using the micro.blog service.

Fonts

I did not want to use online fonts.

True, they can look really nice but I didn’t want to use bandwidth on something that could slow down the site or cannot guarantee to work in the coming years. In addition, there are privacy concerns when it comes to web fonts that I didn’t want to contribute to.

After a significant amount of time looking for accessible fonts that are all the major OSes, I went with Verdana for my main text font and Garamond for headers.

Figures

I decided that I wanted the items in a figure to take have the same effect as the articles but take the main background so that it would have a stacking effect.

Labarum figures light mode

Here are some pictures of what the figures looks like in dark mode.

Labarum figures dark mode

Tables

I typically don’t use tables in my writing, but I thought I should add a little bit of styling in case someone else feels the need.

Labarum table light mode

Here it is in and dark mode.

Labarum table dark mode

Tasks lists

This was the hardest part to solve because most of the Hugo themes do not address tasks lists. To be clear, these are static lists created by the writer and not something a reader is expected to interact with.

Labarum task list light mode

Dark mode for the task list.

Labarum table dark mode

Most themes will have something like the following code to remove the markers that show up in an unordered list.

/* task list and its checkboxes */
article ul > li:has(> input[type="checkbox"]) {
    list-style: none;
    margin-inline-start: -1rem;
}

article ul > li:has(> input[type="checkbox"])::before {
    content: "\200B"; /* accessibilty for Safari [developer.mozilla.org/en-US/doc...](https://developer.mozilla.org/en-US/docs/Web/CSS/list-style) */
}

Eventually, I found a wonderful example in the Hugo Relearn theme that was written about on Modern CSS applied it to what I had.

Reflection

I’m happy with the theme.

There are still somethings that I want to improve upon and I invite you all to comment and help me make it better in the future. I’ve also made a post on my test blog that should have a lot of examples of the theme in action.

Creating Labarum (Part 5): Schema and Open Graph

Websites are read by more than just human eyes. Browsers, search engines, screen readers, and more take the information being served to them about a site and use it for different purposes. I wanted to make sure that my site could be parsed properly so that it can be reached to everyone who wants it. The web has several technologies designed for this purpose that do not add too much more work to incorporate them. I focused on Schema and OpenGraph meta1 tags in the <head> element to achieve this. An excellent resource for learning about it can be found at HTML Head.

Preface

Hugo offers ways of doing this by having your template reference some internal templates. For example, the very popular template Ananke uses the following code to utilize these templates.

{{- template "_internal/opengraph.html" . -}}
{{- template "_internal/schema.html" . -}}
{{- template "_internal/twitter_cards.html" . -}}

At the beginning of this process, I found that including this would cause the site not to render on Micro.blog. That issue has since been resolved, but I kept with my code for my understanding and further customization.

The good thing about all of this is that Ananke has a link directly over the templates so that you can review the code yourself.

It can be found here: Embedded Templates

Another key difference is that the templates also have logic for a featured image. In most of my usage, I don’t have images and don’t know how to specify an image as featured in markdown. I’ll have to reevaluate this at a later date.

Heading Home

When creating a template for blog, you should be aware that not all tags that you would have for your articles apply to your main page.

I used a flag that Hugo provides to create a section in the header for the home page to keep tags that a specific t the landing page.

{{- if .IsHome -}}

For the individual articles, I’ll be checking the title property in to determine logic on what tags that will be used.

{{ if isset .Params "title" }}

When you read the article, you will see different times that I specified something and may think that I could have been more clever by writing it in a way where I don’t have to repeat myself. I did this for a few reasons.

  1. I’m learning how Hugo works with templates
  2. I find that clever code can be difficult to debug and understand (You can thank me later, future me)

Getting a head of the page

I wanted to start off with the <head> elements that Micro.blog uses before checking to see if there were other things that I needed to add for the website.

I like to look at the Marfa’s head partial because it’s the theme that Manton uses.

{{ "<!-- Micro.blog Values -->" | safeHTML }}
<link rel="shortcut icon" 
	href="https://micro.blog/{{ .Site.Author.username }}/favicon.png"
	type="image/x-icon" />
<link rel="me" href="https://micro.blog/{{ .Site.Author.username }}" />
<link rel="authorization_endpoint" href="https://micro.blog/indieauth/auth" />
<link rel="token_endpoint" href="https://micro.blog/indieauth/token" />
<link rel="micropub" href="https://micro.blog/micropub" />
<link rel="microsub" href="https://micro.blog/microsub" />
<link rel="webmention" href="https://micro.blog/webmention" />
<link rel="subscribe" href="https://micro.blog/users/follow" />
<link rel="canonical" href="{{ .Permalink }}" />	

A lot of the these values are specific to how Micro.blog and the open web respond to the site in general. Blogging software such as MarsEdit, will use this information to connect to your blog for editing. Webmentions are a way for different systems to communicate to regarding if the source content has been referenced somewhere else.

{{ if .RSSLink -}}
<link href="{{ .RSSLink }}" rel="alternate" type="application/rss+xml" title="{{ .Site.Title }}" />
      <link href="{{ "podcast.xml" | absURL }}" rel="alternate" type="application/rss+xml" title="Podcast" />
      <link rel="alternate" type="application/json" title="{{ .Site.Title }}" href="{{ "feed.json" | absURL }}" />
      <link rel="EditURI" type="application/rsd+xml" href="{{ "rsd.xml" | absURL }}" />
    {{ end -}}

These allow for newsreaders and podcast aggregators to get the information needed to get information about updates. One cool thing is the use of a JSON feed that Manton helped build.

I also found a website dedicated to explaining a lot of the different tags that can be found in the <head> element.

Open examples

The first set of tags that I looked at were ones related to OpenGraph tags. These where the ones that a supported in social media (facebook, twitter, slack, etc.) and operating systems that I was using at the beginning of the project.

OpenGraph tags behave the same way as <title> and other tags in a web page. In fact, for some services, if an OpenGraph tag is not there, it will default to other tags in the head. For example, title or description. I decided to define the values for the tag to make sure that the site is compliant2.

The key difference between OpenGraph tags and the standard tags that you see in the <head> element of a website is that they are defined as <meta> tags. A tag would have a property and content definition that would follow a pattern shown below.

<meta property="PropertyName" content="PropertyString" />

In the examples that I have seen, they often duplicate some of the information that is already there. In most cases, you would see:

<title>Some Title</title>
<meta property="og:title"
  content="Some Title" />

This makes it fairly effortless to get most of the tags together with only a few complications with dates, images, and whether to support twitters extensions.

Dates

A long time ago, some smart people decided that there should be an international standard for representing dates. As of this writing, Hugo doesn’t automatically format the date to this standard.

{{ $iso8601 := "2006-01-02T15:04:05Z07:00" }}

This line defines a string that we can use to later format dates in other parts of the template.

{{- with .PublishDate }}
<meta property="article:published_time" {{ .Format $iso8601 | printf "content=%q" | safeHTMLAttr }} />
{{ end }}

Then when a page is rendered we can see the time and in which time zone.

<meta property="article:published_time" content="2023-03-23T16:50:58-07:00" />

Images

For the home page, we assume that the user wants to use their favicon for their image property.

<meta property="og:image" content="https://micro.blog/{{ .Site.Author.username }}/favicon.png" />

This works fine for home pages, but we want to provide more information for the articles that may have it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{{- with .Params.images -}}
{{ "<!-- .Params.images -->" | safeHTML }}
<meta name="twitter:card" content="summary_large_image" />
{{- range first 6 . }}
<meta property="og:image" content="{{ . | absURL }}" />
<meta itemprop="image" content="{{ . | absURL }}" />
{{- end -}}
{{- else -}}
{{ "<!-- $.Site.Params.images -->" | safeHTML }}
<meta property="og:image" content="https://micro.blog/{{ .Site.Author.username }}/favicon.png" />
<meta itemprop="image" content="https://micro.blog/{{ .Site.Author.username }}/favicon.png" />
<meta name="twitter:card" content="summary" />
{{- end -}}

The first line checks that images exist in the article.

Line 2 creates a comment in the rendered HTML.

Line 3 is specific to twitter makes the images bigger in the timeline.

Line 4 sets up loop over an array. The key words first 6 limits the loop and the . specifies the array as being the images defined in .Param.images.

Line 5 creates the line of html for that particular image we are on in the loop.

Line 8 starts our logic when there are no images attached to the article and defaults to giving the user profile picture.

Other media

Modern sites can also have audio and visual components as well.

{{- with .Params.audio }}{{ range . }}<meta property="og:audio" content="{{ . }}" />{{ end }}{{ end }}

The line looks at all the audio in the article and then adds the following property.

<meta property="og:audio" content="https://micro.blog/pages/downloads/661/1841919/750047.mp3" />

You can also do the same looping code to go over any video that you might have.

{{- with .Params.videos }}{{- range . }}
<meta property="og:video" content="{{ . | absURL }}" />
{{ end }}{{ end }}

And it will render correctly.

<meta property="og:video" content="https://mandarismoore.com/uploads/2021/793e8ba1bb.mp4" />

At the moment, I don’t have an examples of a system processing this information, but I’m happy knowing that it’s there.

The Twitter Question

As I was working on this, Twitter was acquired by Elon Musk. There were numerous layoffs and I honestly don’t know if I should put in the time to make sure that I support the twitter specific extensions to the OpenGraph specs. Ultimately, I added them in case someone uses this theme and shares the links on Twitter.

Micro.blog allows a user to add their twitter name and I used that to populate both twitter:site and twitter:creator.

1
2
3
4
5
{{ with .Site.Params.twitter_username }}
<link rel="me" href="https://twitter.com/{{ . }}" />
<meta name="twitter:site" content="@{{ . }}" />
<meta name="twitter:creator" content="@{{ . }}" />
{{ end }}

If the user doesn’t have a twitter username, this code will not be included during the rendering of the website.

Scheming

The key difference between OpenGraph and Schema tags is that they use different tags to represent the same information.

A schema meta tag will usually look like the following.

<meta itemprop="PropertyName" content="PropertyString" />

This is basically the same idea but implemented by different groups. When I first learned of Schema tags, I was told that it was used by search engines to parse information. When I attempted to verify this, half the tools used to check have been shutdown or made reference to using OpenGraph.

Still, I wanted to include them as the logic was already completed during my implementation of OpenGraph tags.

In addition to the meta tags, you will see the schema tags in the article itself.

For example, in the <span> tags of the article footers for the different dates and categories.

<span itemprop="articleSection">{{ $Category }}</span>

Currently, I’ve mixed in all the schema tags with the OpenGraph tags to make sure that I have parity between the two where it makes sense.

Evaluating

For open graph testing, I created a page on the test version of my site using the two following tools.

https://opengraphr.com/open-graph-debugger

https://www.opengraph.xyz/

Schema

I used https://validator.schema.org to test Schema.

Accessibility

I used https://wave.webaim.org to test for accessibility. I did get some alerts with the design because I had some video and audio tags but no transcripts. Another issue is the contrast that I used for the Permalinks on dates. I’ll work on that in a future release.

twitter

The twitter official validator is https://cards-dev.twitter.com/validator. NOTE Removed as of mid 2022. You have to post the link in the composer window of a tweet to see what it will look like.

Opportunities to grow

During the writing of this article, I found numerous ways that I can improve my theme. So much, that I had stopped development because I didn’t want the article and theme to become too separate from each other.

To continue with development without worrying about this, I’ve tagged the version of the code for the time that these steps of the article were created. You can find the link below.

Labarum 1.0.1

In the meantime, I’ll be cleaning up the code so that the Hugo Theme is easier for me to read and that the rendered output as well.

I tested the accessibility of the site, and it did have a decent score, but I’d really like to improve the fonts and colors.

You are welcome to follow this site or the Labarum category to see updates when this is updated. And you can always contact me here or via email!

Creating Labarum Part 1: Design and initialization

Creating Labarum Part 2: Creating the individual posts

Creating Labarum Part 3: Implementing post footer

Creating Labarum Part 4: Initiating the Index


  1. I don’t like the fact that Facebook changed it’s name to meta. ↩︎

  2. Meaning that all the tags are valid html tags. ↩︎

Creating Labarum (Part 4): Initiating the Index

In the beginning of this series, we started off with an index page that was just a static page with one line that stated you were on the index page. When it comes to implementing this, I looked at the Hugo Themes Free as well as the theme gallery that Micro.blog provides.

Ultimately, I went with a simple structure that took advantage of the simplicity that I had in the Pure theme and the fact that we had already extracted the logic for articles into the partials.

{{- range ( .Paginate (where .Site.RegularPages "Type" "post")).Pages }}
{{ partial "article.html" . }}
{{ end }}

After that, we remove all the static <article> tags that we placed into our index to see how it renders. This looks ok, but the design that I have in mind calls for pagination1(being able to go to older posts).

Paging the index

I admit that I went down a rabbit hole of different examples of how to create the navigation that you see at the bottom of the page. A lot of the examples that I came across where hard coded or I couldn’t understand.

Ultimately, I went with the example that I had from my previous theme. I took the code and placed it into a file name partial\site-navigation.html so that I can track it later.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{{ "<!-- Site Pagination -->" | safeHTML }}
{{ $paginator := .Paginate (where .Data.Pages.ByDate.Reverse "Type" "post") (index .Site.Params "archive-paginate" | default 10) }}
<nav class="pagination">
	{{- if $paginator.HasPrev -}}
	<p class="nav_prev">
		<a href="{{ $paginator.Prev.URL }}" title="Previous Page" rel="prev">
		← Newer Posts
		</a>
	</p>
	{{- end }}

	{{ if $paginator.HasNext -}}
	<p class="nav_next">
		<a href="{{ $paginator.Next.URL }}" title="Next Page" rel="next">
		Older Posts →
		</a>
	</p>
	{{- end }}
</nav>

On the first line, I’m adding a line that will show up in the final output of the generated site so I can see where Hugo is inserting the code.

The second line calls the default paginator to go over all the posts that the site has by whatever parameter that is given. If none is given, it will use 10.

Line 3 defines our semantic element for the navigation and give it a class for styling it later.

Line 4-10 tests to see if there is a previous page and then creates a link to the page when it exists.

Line 12-18 tests to see if there is a next page and creates everything that’s needed.

The navigation was another thing that I spent a lot of time looking into, but ultimately went with a simple ordered list of items.

The initial design did not have a link to the home page because I thought that anyone how came across the page would only be interested in that page and not the additional content, but after having to go to the address bar multiple times to navigate between the different pages, I decided to add it as the first item.

I placed this into a separate file called site-nav.html like I did for pagination for better tracking.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{{ "<!-- site-nav.html -->" | safeHTML }}
<nav>
	<menu>
		{{ if ne .IsHome true }}
		<li><a href="{{ .Site.BaseURL }}" title="{{ .Site.Title }}">Home</a></li>
		{{ end }}
		{{- range .Site.Menus.main }} 
		<li><a href="{{ .URL | relLangURL | safeURL }}">{{ .Name }}</a></li>
		{{ end -}}
		<li><a href="{{ "feed.xml" | absURL }}" rel="feed" type="application/rss+xml" title="{{ $.Site.Title }}">RSS</a></li>
	</menu>
</nav>

On line 3, I used the <menu> semantic tag to give it some more meaning. It definitely felt that it took some time to On line 3, I used the <menu> semantic tag to give it some more meaning. It definitely felt that it took some time to get a consensus on whether I needed to add a <ul> or <ol> to make the syntax valid.

Line 4 does a test to see if the generated page is the home page. This is working to an extent, but fails when moving to the second index page.

Line 7 sorts through the different menu items. I had an issue trying to understand how Hugo puts together a menu on my local copy and what was being used in Micro.blog.

Line 10 gives a direct link to the RSS feed for the site. The RSS feed is inherited from the base blank theme that underlies of Micro.blog.

The next segment of this tutorial will be focused on the schema tags followed by accessibility and then a grab bag of different things.

Please let me know if you have any questions about the design so that I can make this better. I think I might put this all together in one LARGE post at the end.


  1. I’ve come across a couple sites that only have the index and then has the user search or go through an archive to find older material. The argument being that most users only want to read your most current entries or have something specific that they are looking for.

    I’m going to go with what I feel is a classic approach and revisit this later. ↩︎

Creating Labarum (Part 3): Implementing post footer

In my initial design, I had footer that would show the categories, tags, date published, and date modified. All of these values are things, I had seen in previous sites and I could easily get to this information. I thought it would be 15-20 minutes to get this information. The fact that I felt that the footer deserves it’s own discussion should let you know that it ultimately wasn’t.

Start!

The first thing I did was move my current static footer from my example into it’s own template file partials/article-footer.html. I’m going to spare you the boring details of how I searched and searched through examples of what I thought it should look like versus what Hugo provides. A lot the issues that I ran into was whether I was using tag, tags, category, or categories. Do I write the code I write have to parse a comma separate list or an array?

My mental model originally had it so that a post could have one category and multiple tags.

Tag to multiple categories

Unfortunately, after a couple hours I realized that a lot of this was moot because I was going to send this template to Micro.blog and I didn’t know what they used.

Getting more information about Micro.blog

The ultimate goal for this theme is that I’d use it on the Micro.blog service. Although Micro.blog uses Hugo, it has a significant amount of customization that I do not know about. Honestly, I do not want to know exactly how it is put together, but I do want to know what it is sending to the theme to get rendered.

So, this is the point in the process where I deploy all the changes that I’ve made to GitHub and then use the instructions on how to set up with a custom theme.

I took some information from the  Hugo page on debugging a theme and then placed that in a <detail> item nested in the  footer. This made the article.html template pretty long, so I decided to make the footer into its own file (article-footer.html) for easier management.

Ultimately, this allows me to see if Micro.blog supports tags or categories and whether it’s stores in a string or array. I’m going to include the code in this post below.

{{ "<!-- Debugging Details --> " | safeHTML }}
	<details>
		<summary>Debug</summary>
		<h1>Site Properties</h1>
		<pre>
		{{ printf "%#v \n" $.Site  }}
		</pre>

		<h1>site.Params Properties</h1>
		<pre>
		{{ printf "%#v" site.Params }}
		</pre>

		<h1>Permalink</h1>
		<pre>
		{{ printf "%#v \n" .Permalink }}
		</pre>
		
		<h1>Params</h1>
		<pre>
		{{ printf "%s" $.Params }}
		</pre>

		<h2>All variables scoped to the current context</h2>
		<pre>
		{{ printf "%#v" . }}	
		</pre>
	</details>

After that, I’ll set the display of the debug information to hidden in the CSS.

article footer details {
    display: none;
}

I then deploy it to the test blog to see what is going on, I can see that categories is used in templates and is stored in an array.

Opening and closing of detail/summary debug information

If we parse through the debug information, we can find the information about whether Micro.blog uses tags or categories.

Categories defined on a specific post

Categories and Tags

As you have seen, I spend a lot more time of what the different elements make up the different pages. From here, I borrowed1 some code from the internet and rewrote it so that I can hopefully remember what it does in the future.

{{ with .Param "categories" }}
	Categories:

	{{ range $CategoryArray, $Category := (. | sort) }}
		{{ if gt $CategoryArray 0 }}
			<span></span>
		{{ end }}
		<a href="/categories/{{ $Category | urlize }}">{{ $Category }}</a>
	{{ end }}
	
{{ end }}

I also included code for tags that I saw in another example to future proof the theme in case we add tags later on with Micro.blog.

{{- with .Param "tags" }}
{{ with $.Param "categories"}}
<br />
{{ end }}
	Tags: <span itemprop="keywords">
  	{{ range $index, $tag := (. | sort) }} 
  		{{ with $.Site.GetPage (printf "/%s/%s" "tags" $tag) }}
  			<a href="{{ .Permalink }}" class="tag">{{ $tag | urlize }}</a>
  		{{ end }}
	{{ end }}
	</span>
{{- end }}

I didn’t do much with this portion because we don’t use them with Micro.blog, and I’ve got a lot of other things to get working before coming back to this.

Remember the time

Another piece of information that we can get from the debug output is date information from the post. We actually get three different dates: date, publishdate, and lastmod.

On my local server instance, I played with the different logic for if a date was different than another and learned about how Go did comparisons of dates for about an hour.

Then I found out that Micro.blog use the same time for all three…

Labarum raw date format in debug information

You can then put this information into our template.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<p>Published: 
	<a href="{{ .Permalink }}" class="u-url">
	<time class="dt-publised" itemprop="dateCreated datePublished"
		{{ 
		printf `datetime="%s"` (.Date.Format "2006-01-02T15:04:05Z07:00") 
		| safeHTMLAttr }}>
		{{- .Date.Format (default "January 2, 2006" .Site.Params.date_format) }}
	</time>
	</a>
</p>

On line 2, I create a link to the article because this footer will be used single pages and the index and we don’t know if every post will have a title.

Line 5 makes sure that the date is formatted in ISO 8601 so that it can be parsed properly.

Line 7 shows the date in a more human readable way. I made a mental note to look into how I can make it output “6th” but all the examples that I’ve seen do not show in like that.

I wanted the footer to have two separate sections of information; one for categories and tags and the other for dates.

Footer detail mental model

I used a css grid to make the two sections and made sure that the data I add was grouped in a <p> tags.

article footer {
    display: grid;
    grid-template-columns: 2;
}

article footer p:last-of-type {
    grid-column: 2;
    text-align: right;
}

After doing my testing and getting the debug information, I hid the details in the footer.

article footer details {
    display: none;
}

I plan to cover more css when I discuss accessibility later on in the series.


  1. I took this from Pete Moore’s implementation of Tufte. You can read Moore about it here↩︎

Creating Labarum (Part 2): Creating the individual posts

For this part, we’re going to be setting up the basic page used for our post and make sure that it can be reached from the index page. We’re going to be switching between different files to show the iterative process that I went through in order to see results quickly.

We’re going to edit the single.html to show the content by using the &#123;&#123; .Content }} tag from Hugo. We also add the &#123;&#123; .Title }} to the header and link it using the &#123;&#123; .Permalink }} tag to get the following.

<article class="h-entry">
<header>
<h1><a href="{{ .Permalink }}">{{ .Title }}</a></h1>
</header>

<section class="e-content post-body">
{{ .Content }}
</section>

It renders to the following:

Simple article header with title

Let’s go back to our index.html to make it link to our post and show it on the main page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{{ range ( .Paginate (where .Site.RegularPages "Type" "post")).Pages }}

<article>
	<header>
		<h1><a href="{{ .Permalink }}">{{ .Title }}</a></h1>
	</header>
	<section>
		{{ .Content }}
	</section>
	<footer>
		<p>
		Category: <a href="#">Some Category</a><br/>
		Tags: One Two Three
		</p>
	
		<p>Published: Some Date</p>
		</footer>
</article>
	
{{ end }}

The first line in the above code instructs hugo to iterate over all pages marked for the post type. On our local system, this isthe post directory and is in a database when using Micro.blog. The Permalink points to the individual post.

Links between index and post

We can test this by adding more content in the post folder to see what it looks like.

Multiple posts on index

But this highlights, we’re currently writing code in two places: the index.html and the single.html to render our content.

Note the forth line of the code which makes the assumption that we’re using a title for this post.

This is how I envision a post’s composition.

Mental model of post composition

We’d check if a post has a title and from there show a header or not before displaying the content and ultimately the footer.

Abstracting the article from the page

Let’s create partials/article.html and we’ll put all the content that we placed in _default/single.html in it.

<article class="h-entry">
<header>
<h1><a href="{{ .Permalink }}">{{ .Title }}</a></h1>
</header>

<section class="e-content post-body">
{{ .Content }}
</section>

<footer>
	<p>Category: <a href="#">Some Category</a><br/>
		Tags: One Two Three</p>
	
		<p>Published: Some Time</p>
</footer>
</article>

Then we replace the contents of default/single.html with the following.

{{ define "main" }}
{{ partial "article.html" . }}
{{ end }}

When we render the page and there shouldn’t be any errors at this point.

Let’s add the conditional for the header of the article.

{{ if .Title }}
<header>
<h1><a href="{{ .Permalink }}">{{ .Title }}</a></h1>
</header>
{{ end }}

Then let’s make a post without a header to test out that this is working without an error in our logs.

Simple article without a header

Next, we can work on the article footer which I’ll make into a separate component in the next installment.

Creating Labarum (Part 1): Design and initialization

I wanted to create a new theme for Micro.blog, and I thought I would document all the steps that I went through. The creation of the theme was an iterative process for me and this tutorial works in that way. I’m also not a web designer and I’ve focused mostly on the technical aspect of this theme. This theme and tutorial were put together over the span of a couple months and things changed both in some of the technical aspect and how I thought of the theme.

Design Goals

The first thing I wanted to make sure of was that my theme would be accessible. I want people who use a screen reader to be able to navigate the site without a problem and meet the latest standards as defined by WCAG.

Secondly, I wanted the site design to be semantically correct. I understand that many designers used dev tags for a lot of their design and architecture, but I wanted people who come to my website to be able to read the source and learn from it.

Third, I want to be able to make the design that has been siting in the back of my mind for a while. I’ve been enjoying minimal designs for years. I think this is mostly in part from my years experiencing dial-up and having to sit there and wait for the site to render because whoever paid for it needed me to see their huge logo and hero images.

This is what I’ve been picturing for the main page.

The first sketch of what I wanted the site to look like.

This is what I’d like to have for individual pages.

Sketch of the individual page

Understanding Micro.blog

To make it clear, I do not want to know what the secret sauce that Manton applies to make the whole site work. I know I would continually want to dabble. Manton has really done some magic to make Micro.blog work as both a blogging platform and social network. I feel that it offers an exciting mix of features without me having to spend a lot of time doing a lot of the technical configuration that I both equally hated and enjoyed.

But old habits tend to die hard and I found myself wanting to customize my own site and Micro.blog allows you to do that. When I look at new projects, I tend to visualize how the different components come together. For me - as it is near Christmas at the time of this writing - I think of Micro.blog as a Christmas tree.

Mental model of Micro.blog components

I do want to have an understanding of how themes are put together so that I can customize it. The beauty of working with this system is that every thing that I’ll be doing to customize will be backed by the Blank theme. I also only want to focus on how the site is generated. Every thing else, I leave to Manton Magic.

Setting up my local environment

The first thing that I did was make sure that I had Hugo installed on my machine using Homebrew. I did this to get an understanding of Hugo which is a big part of Micro.Blog. At the beginning of this project, you had to make changes to the Git repository that your theme was hosted on and then add it as a new theme in Micro.blog to see it refresh. I thought that if I do most of the initial development on my system, I could save time with doing smaller iterations on my home system.

Terminal window running hugo command

It’s a slightly older version than what Micro.blog (v91) is using, but I didn’t want to spend too much time in getting the versions to match up after spending some time reading what the key differences were.

From there I used the standard Hugo command to create a new environment.

hugo new site labarum-hugo

I create a project in GitHub called Labarum and cloned it in the themes directory of the new Hugo site. The was mostly to the .gitignore and README without making my own, but I see that it didn’t include the .DS_Store so I’ll add that as my first local commit1.

I then created smaller repository to host a little html and css experiments called tryout so that could iterate on the design with a static site.

Basic Structure

For the first iteration, I took a lot of the structure from my previous projects2 and just made the basics of what I wanted to be the following.

<html>

<head>
	<meta charset="utf-8">
    <meta name="viewport" content="width=device-width initial-scale=1">

    <title>Boxes</title>
	<link rel="stylesheet" href="./css/normalize.css" />
	<link rel="stylesheet" href="./css/style.css">
    <link rel="stylesheet" href="./css/custom.css">
</head>


<body>

<nav>
	<menu>
		<li><a href="#">Home</a></li>
		<li><a href="#">About</a></li>
		<li><a href="#">Contact</a></li>
		<li><a href="#">Toggle</a></li>
	</menu>
</nav>

<main>
<article>
	<header>
		<h1><a href="#">First Article Title</a></h1>
	</header>
	<section>
		<p>This is the main body of the article.</p>
	</section>
	<footer>
		<p>This is the article footer</p>
	</footer>
</article>
</main>
<footer>
	<p>Footer for the site</p>
</footer>
</body>

</html>

Please note that I added a note to normalize.css. I thought it was interesting that a lot of the themes that I see in the Hugo theme library link to a version of normalize, but it didn’t seem like it was the latest. I don’t know if they are just optimizing for classes that aren’t in most sites, but I thought I would take the version from the GitHub repository and make it part of my theme. I feel that you never know what the end user of this theme is going to use it for and this will cover most cases and they can change the rest.

Initial Designs and Iterations

I also took some of the colors from the Pure project I was working on to help me figure out how I wanted some of the colors to look.

This is the first iteration of light mode.

This actually took me a lot more time than I thought.

Then I thought I’d put some time into the dark theme.

Labarum first draft dark mode

During the first iteration, I also decided to drop the heading for the page as I felt that if someone came to my page they would be more interested in the articles than what the title was.

For the second iteration on the design, I added places more information about the categories, tags, and the dates something was published and modified. I played around with using a details and summary tag, but it was getting a little too much outside of my abilities and I wanted to move on to other portions of the design.

This should give the user quick access to pertinent information.

If you noticed, I haven’t put any work towards the navigation yet. I thought that I would see what the site looks like when some test content before I decide on it.

But first it’s important to start moving this into a template.

For Hugo, you need to have layouts/_default/baseof.html. We’ll take the entire example that we were working on and put it in the same format that Hugo is expecting.

Folder structure of theme in bbedit

In the baseof.html, we’ll add the following block.

{{ block "main" .}}{{ end }}

Then we create a layouts\index.html file for later version of Hugo with the following content:

{{ define "main" }}
<p>This is the index page</p>
{{ end }}

Then when we run hugo server -D on the command line, the page will render and you might see something like the following.

~/Code/labarum-hugo
❯ hugo server -D
Start building sites …
hugo v0.94.2+extended darwin/amd64 BuildDate=unknown
WARN 2022/06/16 21:11:52 found no layout file for "HTML" for kind "taxonomy": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.
WARN 2022/06/16 21:11:52 found no layout file for "HTML" for kind "taxonomy": You should create a template file which matches Hugo Layouts Lookup Rules for this combination.

The site should look like the following at this point.

Index page with an article on it

Pretty plain. And -again- this is mostly the static content that I created.

Let’s get rid of the warnings first, that way, we can focus on anything that pops up as we build the rest of the template.

Creating taxonomy/list pages

Let’s go to the Hugo’s documentation on template lookup order and search for taxonomy, and it lists different options. I think we’ll make layouts/_defaults/list.html which matches what we see with the base template that blank template that micro.blog provides.

We’ll just stub it for now.

{{ define "main" }}
<p>This is the basic list.html file</p>
{{ end }} 

Now we have a “clean” build of our site that shows pretty much nothing other than the box example that we created.

We can start the Hugo server and go to /posts/ to see the new posts page.

Labarum list html with no css

Notice that it doesn’t have the css linked properly. This is because our css used ./css and we have to remove the dot so that Hugo serves in properly. There are other ways of referencing this that we’ll look into later in this series.

We can now get really started!

Let’s make our first post by using the “Add Some Content” step from the Hugo Quick start.

After creating the content, we run the hugo -D command if the server isn’t running to get the output. At this point, we see another warning about pages.

❯ hugo -D
Start building sites …
hugo v0.94.2+extended darwin/amd64 BuildDate=unknown
WARN 2022/07/05 18:19:20 found no layout file for "HTML" for kind "page":
You should create a template file which matches Hugo Layouts Lookup Rules for this combination.

We go back to the template look up and find the information on making a page. We’ll just make a simple stub for now.

{{ define "main" }}
<article>
<header>
<h2>Article Title</h2>
</header>

<section>
{{ .content }}
</section>

</article>

{{ end }}

Now when we run, we don’t see any warning!

But.

It doesn’t do anything dynamic at this point and all we see is a page with just one line of text.

We’ll have to do that in the second part. Please give me some feed back before I push out the next part two days from now.


  1. This is part of my global ignores but I wanted to make sure that it’s there for people cloning the project in the future of if I forget. ↩︎

  2. I was luckily enough to work on the Pure theme. ↩︎