Hugo

Prison Architect

Table of Content:

Hope lies within you, and only you.

I'm not even done setting up my blog while writing this and that's exactly why it's the perfect time to write. If you haven't read my post about HTML, I concluded that HTML5 was to be used instead of anything else. HOWEVER, when it comes to the automatic generation of a page, I can't help but choose XHTML in that regard. Well XHTML5 that is. I made the realization while coding my sitemap generator. It's a python script – I haven't coded in python in forever and made many mistakes. The good news was my terminal would tell me If and Where I had made a mistake. So in case the script was fine but not the generated page, I wanted the same type of error handling. The XML parser was then the only logical tool to use. Granted it's a bit overkill for such a small project, It's still a good habit to have.

There, I finally found a real use case for XHTML – and I wanted more.

Hugo

My blog is autogenerated by Hugo as I grew tired of reading through my tag soup in HTML. Hugo generates blog pages from Markdown files; it's much easier to code and read so it became an elegant choice. The problem with Hugo is that there are no good themes for it. I mean… Reading layouts? Having to adapt to someone else's logic? When Hugo is extremely well documented and in fact quite easy to use?

So started the creation of my own theme.

XHTML

I like to think that my machines are very very dumb. When generating HTML from a program, I want it perfectly errorless, that means XHTML. Hugo does not natively support XHTML but custom MIME types can be configured1. That was my first objective and so changed my config.toml file:

[outputFormats]
  [outputFormats.xhtml]
    baseName = 'index'
    isHTML = true
    mediaType = 'application/xhtml+xml'

[mediaTypes]
  [mediaTypes.'application/xhtml+xml']
    suffixes = ['xhtml']

Then I needed to change the extension of hugo's output like so:

[outputs]
  home = ['xhtml', 'rss']
  page = ['xhtml']
  rss = ['rss']
  section = ['xhtml']
  taxonomy = ['xhtml']
  term = ['xhtml']

Ok great, Hugo crashes now.

Markup Handler

The default markup handler is Goldmark2. It's very handy because it has an XHTML setting that if set to true will close Null End Tags and nest other tags properly. However, Goldmark's typographer isn't compatible with XHTML by default in Hugo, luckily we can configure it. XHTML cannot parse named HTML entities such as … or «, so in the configs I had to replace those entities with their decimal counterparts:

[markup]
  defaultMarkdownHandler = 'goldmark'
    [markup.goldmark.parser.attribute]
      block = false
      title = true
    [markup.goldmark.renderer]
      hardWraps = false
      unsafe = false
      xhtml = true
    [markup.goldmark.extensions.typographer]
      apostrophe = '''
      disable = false
      ellipsis = '…'
      emDash = '—'
      enDash = '–'
      leftAngleQuote = '‹'
      leftDoubleQuote = '“'
      leftSingleQuote = '‘'
      rightAngleQuote = '›'
      rightDoubleQuote = '”'
      rightSingleQuote = '’'  

If ‘unsafe’ is set to true, it allows raw HTML to be written in your markdown pages. I feared it would break at some point with XHTML so I limited myself to raw Markdown.

HTML

Once I was sure my layout would parse nicely, I always planned on making an HTML version of the theme so I could minify it. In fact Hugo can do that for me3:

[minify]
  minifyOutput = true
  [minify.tdewolff]
    [minify.tdewolff.css]
      keepCSS2 = false
    [minify.tdewolff.html]
      keepEndTags = false

‘keepCSS2’ is set to false because most of us use CSS3 anyway and don't pay much attention to coding backwards compatible CSS. Unless you do, you can set it to true yourself.

The layout itself

Classic summary, read more etc… I mean, you can just browse the site and see for yourself. Or you can check the source code. Make sure you know all about the Hugo variables first.4

Here's a list of features:

It's pretty basic, if you read the code you'll see a bunch of if statements YandereDev5 style but hey, it doesn't bloat the output so whatever.

More on sitemap.html

There's probably a better way to do this but at least it works with a few janky workarounds:

To generate some other type of static page, you need to create new layouts in a 'types’ folder of any name (/else/ in my theme).6

My sitemap layout is used like the default layout aka everything else; it formats Markdown files.

Therefore A sitemap.md file must be created by the user (you) and must be configured to use the sitemap layout. The top of the file should look like so:

+++
slug = 'sm'
layout = 'sitemap'
title = 'Sitemap'
type = 'else'
+++

Do NOT add content to the sitemap page, the sitemap is split in two sections: “Pages” and “Blog Entries”. To achieve this, the site checks whether a page has content or not. Since I strictly write content in my blog posts I decided to keep it simple for myself.

It is IMPERATIVE that the sitemap has the exact title “Sitemap” with a capital S. To hide the sitemap from the list of blog posts I simply added an if statement to exclude its name, and that name is “Sitemap”.

It must have a slug set to “sm” as it is the referer used in the header menu, otherwise our sitemap would be in /sitemap/ and would conflict with Hugo's sitemap generation7.
Hugo generates another type of sitemap for us, it's an XML file you give to search engines for indexation. So ideally you want both sitemaps.

Without content and with the right name, the sitemap page may rightly be listed within itself. The sitemap that is.

The <main> has a “sitemap” id so you can edit CSS easily.

Otherwise you can disable the sitemap thing altogether in your hugo.toml file. This theme's config.toml includes variables you can copy to do so.

Here they are:

title = "Website Name" #name of your site
baseURL = 'https://example.org'
languageCode = 'en-us'
copyright = 'Made with Cleogo' #displayed in the footer

[params]
  # copyright href
  cphref = "https://github.com/Cleomancy/cleogo/"

  favicon = "/favicon.ico"

  # toggle menu and or just parts of it.
  menu = true
  tags = true
  sitemap = false
  categories = true

[markup]
  defaultMarkdownHandler = 'goldmark'

    [markup.goldmark.parser.attribute]
      block = false
      title = true
    [markup.goldmark.renderer]
      hardWraps = false
      unsafe = false
      xhtml = false
    [markup.goldmark.extensions.typographer]
      apostrophe = '&#39;'
      disable = false
      ellipsis = '&#8230;'
      emDash = '&#8212;'
      enDash = '&#8211;'
      leftAngleQuote = '&#8249;'
      leftDoubleQuote = '&#8220;'
      leftSingleQuote = '&#8216;'
      rightAngleQuote = '&#8250;'
      rightDoubleQuote = '&#8221;'
      rightSingleQuote = '&#8217;'

[outputFormats]
  [outputFormats.xhtml]
    baseName = 'index'
    isHTML = true
    mediaType = 'application/xhtml+xml'

[mediaTypes]
  [mediaTypes.'application/xhtml+xml']
    suffixes = ['xhtml']

[outputs]
  home = ['html', 'rss']
  page = ['html']
  rss = ['rss']
  section = ['html']
  taxonomy = ['html']
  term = ['html']

[minify]
  minifyOutput = false
  [minify.tdewolff]
    [minify.tdewolff.css]
      keepCSS2 = false
    [minify.tdewolff.html]
      keepEndTags = false

That's all. Thank you.


  1. Custom media types configuration ↩︎

  2. Markup configuration & Goldmark docs ↩︎

  3. Minify configuration ↩︎

  4. Hugo Variables ↩︎

  5. Drink from me… ↩︎

  6. Hugo Layouts ↩︎

  7. Hugo Sitemap generation ↩︎

Related tags:
Technical