Hugo Templates
Table of Contents
Introduction
This collection of Hugo templates is a draft: it is considered incomplete and
there are plans to add or change information contained in it. Pay
special attention to text flagged DRAFT
, EDIT
, REVIEW
, or TK
.
This is a collection of templates (and other resources) for use with, Hugo, a static site generator.
This collection of Hugo templates was written by me, emsenn, and is released for the benefit of the public under the terms included in the "License" supplement. It was made possible with financial contributions from humans like you. If you would like to offer corrections or opinions about this collection of Hugo templates, please send an email to my public inbox or, if appropriate, my personal email.
This collection of Hugo templates includes a "Further Reading" supplement which includes recommended texts for those who want to know more about the topic(s) being covered. If you know of a freely-available resource that should be included, please send an email to my public inbox or, if appropriate, my personal email.
This document was written primarily as a personal reference for the author. It may assume an uncommon familiarity with the topics and context being discussed. If you are trying to use this document and find a part unhelpful, please submit an email to the author's public inbox.
This collection of Hugo templates is implemented using the literate programming paradigm. The "software" being presented is included as sections of code, within a longer piece of prose which explains the code's purpose and usage. For a more complete explanation of my implementation of the paradigm, see "Literate Programming" in my Style Manual.
Hugo Templates
Using this File
At the moment this file isn't ready for use! Sorry. Maybe there's useful snippets, though?
Hugo Configuration
This section covers what's expected in the configuration file of a site using these templates. If you're not using all of the templates, you might not need all of these things set.
Base URL Configuration
The baseURL
variable is accessed through .Site.BaseURL
.
baseURL
is currently unused.
baseURL = "https://emsenn.net"
Language Configuration
The languageCode
variable is accessed through .Site.Language.Lang
.
languageCode
is used in the "Default Base Layout".
languageCode = "en-us"
Emoji Configuration
The enableEmoji
variable sets whether or not emoticon shortcodes in
documents are rendered. (:smile: to a smiling face emoji, for example.)
There are currently no templates which use emoji, but site content
might so it is recommended to set it to true
.
enableEmoji = true
Title Configuration
The title
variable is accessed through .Site.Title
.
title
is used in…
title = "emsenn"
Site Author Configuration
The author
variable is accessed through .Site.Author
.
author
is used in…
author = "emsenn"
Site Document Types Configuration
The documentTypes
variable is accessed through
.Site.documentTypes
. Document types,
a category of a text based on its form, are used to guide what templates are
used to construct and style a document.1
[params] documentTypes = "essay fiction document letter manual"
Hugo Layouts
Layouts are the instructions Hugo uses to construct a document.
Explanation TK.
If you're familiar with SMACSS, layouts are equivalent to its' blocks.
Default Layouts
The default layouts, located under ./layouts/_default/
are used
when there's not a more relevant layout to use with a document. See
"Hugo's Lookup Order" in the Hugo Documentation.
Because Hugo is written as a static website generator, all the default templates are in HTML.
Default Base Layout
The base default layout, saved as
./layouts/_default/baseof.html
, is the lowest-priority (except for
themes') base template, but even so is used as the base template for
every(?) HTML document on my website.
There are roughly two parts to the baseof.html
layout - there is
some initialization of variables at the top, and then the rest pulls
in other layouts to render a complete HTML document.
Default Base Layout: Document Declaration
{{ block "documentDeclaration" . }} <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" {{- with .Site.Language.Lang }} xml:lang="{{- . -}}" lang="{{- . -}}" {{- end }}> {{ end }}
Default Base Layout: Document Head
The default base layout creates a head
block, which, in its default,
contains a <head>
tag with several components.
{{ block "head" . }} <head>
{{ block "headLinks" . }} <link href="https://gmpg.org/xfn/11" rel="profile"> {{ end }}
The headMeta
block contains a <link>
tag that I honestly don't
know why or what it does, and several <meta>
tags. Setting the
charset
property does… something. I think maybe lets emoji be
available? Or tells the client to try and make them available?
{{ block "headMeta" . }} <meta charset="UTF-8">
The description
is used by search engines and other external resources
if they don't have a more relevant description to pull.
<meta name="description" content="">
The keywords
are used for SEO bullshit.
<meta name="keywords" content="{{- .Render "keywords" -}}">
The author
is set only if the document has an author
parameter set
or if the config.toml
contains a ~author= configuration.
{{ with ((.Params.author) | default (.Site.Author)) -}} <meta name="author" content="{{ . }}"> {{- end }}
<meta name="viewport" content="width=device-width, initial-scale=1.0"> {{ end }}
{{ block "headTitle" . }} <title> {{- printf "%s%s" (.Site.Title) (printf ": %s" (((.Data.Term | pluralize) | default .Title)) | default "") -}} </title> {{ end }}
{{ block "style" . }} <style> {{ block "htmlCSSRules" . }} html { {{ block "htmlCSSColorRules" . }} color: #444; background-color: #eee; {{ end }} hyphens: auto; font-family: sans-serif; letter-spacing: .03em; word-spacing: .05em; line-height: 1.4; font-size: 1.3rem; transition-timing-function: ease-in; animation-timing-function: ease-in; } {{ end }} {{ block "bodyCSSRules" . }} body { margin: 0; {{ block "bodyExtraCSSRules" . }} <!-- --> {{ end }} } {{ end }} {{ block "headerCSSRules" . }} header { overflow: hidden; padding: 1rem 0 3rem 0; background: linear-gradient(to bottom, #eeef 92%, #eee0); } {{ end }} {{ block "mainCSSRules" . }} main { width: 80vw; max-width: 40rem; margin: -4rem 1em -6rem; padding: 3rem 2rem 6rem; {{ block "mainCSSColorRules" . }} background: linear-gradient(to right, #eee0, #eeef 02%, #eeef 98%, #eee0); {{ end }} {{ block "mainExtraCSSRules" . }} {{ end }} } {{ end }} {{ block "footerCSSRules" . }} footer { padding: 4rem 1rem 1rem; background: linear-gradient(to top, #eeef 97%, #eee0); } {{ end }} {{ block "sectionCSSRules" . }} {{ end }} {{ block "headlineRules" . }} {{ block "h1CSSRules" . }} h1 { font-weight: normal; font-size: 2.6em; line-height: 1; {{ block "h1CSSShadowRules" . }} text-shadow: .05em .05em .1em rgba(68,68,68,.3); {{ end }} margin: 0 auto; padding: 0 .5em; } {{ end }} h2,h3,h4,h5,h6 { {{ block "headlineCSSShadowRules" . }} text-shadow: .08em .03em .03em rgba(68,68,68,.3); {{ end }} } {{ block "headlineCSSBeforeRules" . }} h2::before, h3::before, h4::before, h5::before, h6::before, h7::before, h8::before, h9::before, h10::before { display: inline-block; text-shadow: none; {{ block "headlineCSSBeforeColorRules" . }} opacity: 0.5; {{ end }} margin-right: .3em; font-size: 0.6em; } {{ end }} {{ block "h2CSSRules" . }} h2 { font-size: 2.3em; } h2::before { content: "*"; } {{ end }} {{ block "h3CSSRules" . }} h3 { font-size: 2.1em; } h3::before { content: "**"; } {{ end }} {{ block "h4CSSRules" . }} h4 { font-size: 1.9em; } h4::before { content: "⁂"; } {{ end }} {{ block "h5CSSRules" . }} h5 { font-size: 1.7em; } h5::before { content: "⁂*"; } {{ end }} {{ block "h6CSSRules" . }} h6 { font-size: 1.5em; } h6::before { content: "⁂**"; } {{ end }} {{ block "h7CSSRules" . }} h7::before { content: "⁂⁂"; } {{ end }} {{ block "h8CSSRules" . }} h8::before { content: "⁂*"; } {{ end }} {{ end }} {{ block "aCSSRules" . }} a { color: #31B; text-decoration: underline dotted #4447; text-shadow: 0 0 .1em rgba(68,68,68,.2); } a:visited { color: #718; } a:hover { color: #42C; outline-style: none; text-decoration: underline solid #42c3; text-shadow: 0 0 .1em #31b7; } a:focus { color: #42C; outline-style: none; text-decoration: underline solid #42c3; text-shadow: 0 0 .1em #31b7; } a:visited:hover, a:visited:focus { color: #918; text-decoration: underline solid #9183; text-shadow: 0 0 .1em #7187; } {{ end }} {{ block "skipToContentCSSRules" . }} .skipToContentLink { opacity: 0; position: absolute; } .skipToContentLink:focus{ opacity:1 } {{ end }} {{ block "selectionCSSRules" . }} ::selection { color: #222; background-color: #777; } {{ end }} {{ block "imgCSSRules" . }} img { width: 100%; } {{ end }} {{ block "extraCSSRules" . }} {{ end }} </style> {{ end }}
</head>
{{ end }}
Default Base Layout: Document Body
{{ block "body" . }} <body>
{{ block "bodyBackground" . }} <!-- --> {{ end }}
{{ block "bodyPreface" . }} <a class="skipToContentLink" href="#content">Skip to Content</a> {{ end }}
{{ block "header" . }} <header> {{ block "headline" . }} <h1>{{ .Title | default .Site.Title }}</h1> {{ end }} {{ block "subheadline" . }} <!-- --> {{ end }} {{ block "headerExtra" . }} <!-- --> {{ end }} </header> {{ end }}
{{ block "main" . }} <main id="content"> {{ block "content" . }} {{ with .Content }} {{ . }} {{ end }} {{ end }} {{ block "sectionlisting" . }}{{ end }} </main> {{ end }}
{{ block "footer" . }}
{{ end }}
</body>
{{ end }}
Default Base Layout: Document Close
</html>
Default List Layout
{{ define "headline" }} <h1>{{ (.Data.Term | title | pluralize) | default .Title }}</h1> {{ end }} {{ define "sectionlisting" }} {{ with .Pages }} <ul> {{ range . }} <li> <a href="{{ .Permalink}}"><strong> {{- if (eq .Kind "taxonomy") -}} {{- .Title | pluralize -}} {{- else -}}{{- .Title -}}{{- end -}} </strong></a><br/> </li> {{ end }} </ul> {{ end }} {{ end }}
Default Single Page Layout
{{ define "subheadline" }} <!-- --> {{ end }} {{ define "content" }} {{ with .Content }} {{ . }} {{ end }} {{ end }}
Default Index Layout
{{- define "headTitle" -}} <title>emsenn</title> {{ end }} {{- define "headline" -}} <h1>My name is emsenn</h1> {{- end -}} {{- define "subheadline" -}} <!-- --> {{- end -}} {{ define "content" }} {{ with .Site.Data.index.introduction }} {{ . | markdownify }} {{ end }} {{ with .Site.Data.activities }} <section id="recent-activites"> <h2>Recent Activities</h2> <ul> {{ range $date, $report := . }} <li> {{ (printf "**%s,** %s" (dateFormat "January 2, 2006" $date) $report) | safeHTML | markdownify }} </li> {{ end }} </ul> </section> {{ end }} {{ with .Site.Data.index.plans }} <section id="plans"> <h2>Plans</h2> <ul> {{ range . }} <li> {{ . | markdownify }} </li> {{ end }} </ul> </section> {{ end }} <p> {{ (printf "This website contains a [curated list of my projects](/projects/) and [my non-commissioned documents](/docs/).") | markdownify }} </p> {{ end }}
Document Layouts
Default Document Layouts
Default Single Document Layout
{{ define "bodyBackground" }} <div class="backgroundimage"></div> {{ end }} {{ define "bodyExtraCSSRules" }} background-image: url("data:image/svg+xml,%3Csvg width='84' height='48' viewBox='0 0 84 48' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h12v6H0V0zm28 8h12v6H28V8zm14-8h12v6H42V0zm14 0h12v6H56V0zm0 8h12v6H56V8zM42 8h12v6H42V8zm0 16h12v6H42v-6zm14-8h12v6H56v-6zm14 0h12v6H70v-6zm0-16h12v6H70V0zM28 32h12v6H28v-6zM14 16h12v6H14v-6zM0 24h12v6H0v-6zm0 8h12v6H0v-6zm14 0h12v6H14v-6zm14 8h12v6H28v-6zm-14 0h12v6H14v-6zm28 0h12v6H42v-6zm14-8h12v6H56v-6zm0-8h12v6H56v-6zm14 8h12v6H70v-6zm0 8h12v6H70v-6zM14 24h12v6H14v-6zm14-8h12v6H28v-6zM14 8h12v6H14V8zM0 8h12v6H0V8z' fill='%23444' fill-opacity='0.05' fill-rule='evenodd'/%3E%3C/svg%3E"); {{ end }} {{ define "mainExtraCSSRules" }} {{ end }} {{ define "content" }} {{ block "frontmatter" . }} {{ $scratch := newScratch }} {{ ($scratch.Set "contentType" (printf "%s" (.Param "contentType" | default (.Layout | default (.Type | singularize))))) }} {{ ($scratch.Set "showListItems" "") }} {{ ($scratch.Set "showDate" "essay note") }} {{ ($scratch.Set "showReadingTime" "essay letter manual procedure procedures") }} {{ ($scratch.Set "showWordCount" "essay letter manual procedure procedures") }} {{ ($scratch.Set "paramTypes" slice) }} {{ if (isset .Params "tags") }} {{ with .Params.tags }} {{ range last 1 . }} {{ if (eq (. | title) .) }} {{ ($scratch.Set "contentSubject" (. | humanize | title)) }} {{ else }} {{ ($scratch.Set "contentSubject" (. | humanize | lower)) }} {{ end }} {{ end }} {{ end }} {{ end }} {{ with ($scratch.Get "contentType") }} {{ if (eq . ( . | pluralize)) }} {{ ($scratch.SetInMap "grammar" "article" "these") }} {{ ($scratch.SetInMap "grammar" "hasTense" "have") }} {{ ($scratch.SetInMap "grammar" "isTense" "are") }} {{ else }} {{ ($scratch.SetInMap "grammar" "article" "this") }} {{ ($scratch.SetInMap "grammar" "hasTense" "has") }} {{ ($scratch.SetInMap "grammar" "isTense" "is") }} {{ end }} {{ end }} {{ if (in ($scratch.Get "showDate") ($scratch.Get "contentType")) }} {{ with .Date }} {{ ($scratch.SetInMap "pageParameters" "1date" .) }} {{ end }} {{ end }} {{ if (in ($scratch.Get "showListItems") ($scratch.Get "contentType")) }} {{ end }} {{ if (in ($scratch.Get "showWordCount") ($scratch.Get "contentType")) }} {{ ($scratch.SetInMap "pageParameters" "3wordCount" .WordCount) }} {{ end }} {{ if (in ($scratch.Get "showReadingTime") ($scratch.Get "contentType")) }} {{ ($scratch.SetInMap "pageParameters" "4readingTime" .ReadingTime) }} {{ end }} {{ if (.Draft) }} {{ ($scratch.SetInMap "pageParameters" "5isDraft" true) }} {{ end }} {{ ($scratch.Set "introClause" (printf "%s **%s**" ((index ($scratch.Get "grammar") "article") | title) ($scratch.Get "contentType"))) }} {{ with ($scratch.Get "contentSubject") }} {{ ($scratch.Set "introClause" (printf "%s is about **%s** and" ($scratch.Get "introClause") (printf "%s" .))) }} {{ end }} {{ range $k, $v := ($scratch.Get "pageParameters") }} {{ ($scratch.Add "paramTypes" (slice $k)) }} {{ end }} {{ if (gt (len ($scratch.Get "paramTypes")) 1) }} {{ ($scratch.Set "fullDesc" ($scratch.Get "introClause")) }} {{ range first (sub (len ($scratch.Get "paramTypes")) 1) ($scratch.Get "paramTypes") }} {{ if (eq . "1date") }} {{ if $.PublishDate }} {{ if (ne (string $.PublishDate) ("0001-01-01 00:00:00 +0000 UTC")) }} {{ ($scratch.Set "fullDesc" (printf "%s was **released on %s**," ($scratch.Get "fullDesc") (dateFormat "January 2, 2006" $.PublishDate))) }} {{ else }} {{ ($scratch.Set "fullDesc" (printf "%s was **last updated on %s**," ($scratch.Get "fullDesc") (dateFormat "Jan 2, 2006" $.Date))) }} {{ end }} {{ end }} {{ else if (eq . "2listItems") }} {{ else if (eq . "3wordCount") }} {{ ($scratch.Set "fullDesc" (printf "%s %s **%s words**," ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "hasTense") (string (index ($scratch.Get "pageParameters") .)))) | safeHTML }} {{ else if (eq . "4readingTime") }} {{ ($scratch.Set "fullDesc" (printf "%s %s estimated to take **%s minutes to read**," ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense") (string (math.Round (mul (index ($scratch.Get "pageParameters") .) 1.2))))) }} {{ else if (eq . "5isDraft") }} {{ ($scratch.Set "fullDesc" (printf "%s <strong>not finalized</strong>," ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense"))) }} {{ end }} {{ end }} {{ range last 1 ($scratch.Get "paramTypes") }} {{ if (eq . "1date") }} {{ if $.PublishDate }} {{ if (ne (string $.PublishDate) ("0001-01-01 00:00:00 +0000 UTC")) }} {{ ($scratch.Set "fullDesc" (printf "%s was **released on %s**," ($scratch.Get "fullDesc") (dateFormat "January 2, 2006" $.PublishDate))) }} {{ else }} {{ ($scratch.Set "fullDesc" (printf "%s was **last updated on %s**," ($scratch.Get "fullDesc") (dateFormat "Jan 2, 2006" $.Date))) }} {{ end }} {{ end }} {{ else if (eq . "2listItems") }} {{ else if (eq . "3wordCount") }} {{ ($scratch.Set "fullDesc" (printf "%s and %s **%s words**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "hasTense") (string (index ($scratch.Get "pageParameters") .)))) | safeHTML }} {{ else if (eq . "4readingTime") }} {{ ($scratch.Set "fullDesc" (printf "%s and %s estimated to take **%s minutes to read**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense") (string (math.Round (mul (index ($scratch.Get "pageParameters") .) 1.2))))) }} {{ else if (eq . "5isDraft") }} {{ ($scratch.Set "fullDesc" (printf "%s and %s **not finalized**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense"))) }} {{ end }} {{ end }} {{ else if (gt (len ($scratch.Get "paramTypes")) 0) }} {{ ($scratch.Set "fullDesc" ($scratch.Get "introClause")) }} {{ with ($scratch.Get "contentSubject") }} {{ ($scratch.Set "introClause" (printf "%s %s about %s and" ($scratch.Get "introClause") (index ($scratch.Get "grammar") "isTense") ($scratch.Get "contentSubject" ))) }} {{ end }} {{ range first 1 ($scratch.Get "paramTypes") }} {{ if (eq . "1date") }} {{ if $.PublishDate }} {{ if (ne (string $.PublishDate) ("0001-01-01 00:00:00 +0000 UTC")) }} {{ ($scratch.Set "fullDesc" (printf "%s was **released on %s**," ($scratch.Get "fullDesc") (dateFormat "January 2, 2006" $.PublishDate))) }} {{ else }} {{ ($scratch.Set "fullDesc" (printf "%s was **last updated on %s**," ($scratch.Get "fullDesc") (dateFormat "Jan 2, 2006" $.Date))) }} {{ end }} {{ end }} {{ else if (eq . "2listItems") }} {{ else if (eq . "3wordCount") }} {{ ($scratch.Set "fullDesc" (printf "%s %s **%s words**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "hasTense") (string (index ($scratch.Get "pageParameters") .)))) }} {{ else if (eq . "4readingTime") }} {{ ($scratch.Set "fullDesc" (printf "%s %s estimated to take **%s minutes to read**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense") (string (math.Round (mul (index ($scratch.Get "pageParameters") .) 1.2))))) }} {{ else if (eq . "5isDraft") }} {{ ($scratch.Set "fullDesc" (printf "%s %s <strong>not finalized</strong>." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense"))) }} {{ end }} {{ end }} {{ else }} {{ ($scratch.Set "fullDesc" ($scratch.Get "introClause")) }} {{ end }} {{ ($scratch.Get "fullDesc") | markdownify }} {{ end }} {{ block "documentContent" . }} {{ with .Content }} {{ . }} {{ end }} {{ end }} {{ end }} {{ define "footer" }} <footer> <p> My name is emsenn and I wrote this {{ .Layout | default (.Type | singularize) }}. It's released under the {{ .Params.license | default ((printf "[MIT License](https://opensource.org/licenses/MIT)") | markdownify) }}: you can copy it, use it, and redistribute it, for free, for any purpose: personal or commercial. You may <a href="#" onclick="window.print();return false;">print this document</a> or save it locally by pressing <code>Ctrl s</code>. </p> <p> If you found it useful, you might enjoy other {{ (.Layout | pluralize) | default (.Type) }} I've written {{- if isset .Params "tags" -}} , or other pieces tagged with {{- range .Params.tags -}} {{ . }} {{ end }} {{ else }} . {{- end -}} If you have any feedback, please send an email to my <a href="https://lists.sr.ht/~emsenn/public-inbox/">public inbox</a>. </p> <p> This {{ .Layout | default (.Type | singularize) }} was made possible with contributions from humans like you. <a href="/contribute">Thank you.</a> </p> <p> This document was created using <a href="https://www.gnu.org/software/emacs/">Emacs</a>, formatted with <a href="https://orgmode.org/">Org-mode</a>, converted to Markdown by <a href="https://ox-hugo.scripter.co/">Ox-Hugo</a>, built into HTML by <a href="https://gohugo.io/">Hugo</a>, and served by <a href="https://www.neocities.org">Neocities</a>. I created this document's stylesheet, while the background patterns were created by <a href="http://www.heropatterns.com/">Steve Schoger</a>. </p> </footer> {{ end }}
Essay Layout
Fiction Layout
Special Layouts
Teraum Layout
This layout is used for the content piece =docs/teraum.md~, which is a rendering of my fantasy encyclopedia.
{{ define "htmlCSSColorRules" }} color: #444; background-color: #5433; {{ end }} {{ define "bodyBackground" }} <div class="backgroundimage"></div> {{ end }} {{ define "bodyExtraCSSRules" }} background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%239759'%3E%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); {{ end }} {{ define "h1CSSShadowRules" }} text-shadow: .05em .05em .1em #9759; {{ end }} {{ define "headlineCSSShadowRules" }} text-shadow: .08em .03em .03em #9759; {{ end }} {{ define "headlineCSSBeforeColorRules" }} color: #9759; {{ end }}
Ikmu Layout
This layout is used for the content piece =docs/ikmu.md~, which is a about my pet cat, Ikmuwiyula.
{{ define "htmlCSSColorRules" }} color: #444; background-color: #5433; {{ end }} {{ define "bodyBackground" }} <div class="backgroundimage"></div> {{ end }} {{ define "bodyExtraCSSRules" }} background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%239759'%3E%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); {{ end }} {{ define "h1CSSShadowRules" }} text-shadow: .05em .05em .1em #9759; {{ end }} {{ define "headlineCSSShadowRules" }} text-shadow: .08em .03em .03em #9759; {{ end }} {{ define "headlineCSSBeforeColorRules" }} color: #9759; {{ end }}
Project Layouts
Brutstrap Layout
{{ define "style" }} <link rel="stylesheet" type="text/css" href="./projects/brutstrap/brutstrap.css"> {{ end }}
Metapage Layouts
Single Metapage Layout
{{ define "subheadline" }} {{ with .Description }} <p> {{ . }} </p> {{ end }} {{ end }} {{ define "content" }} {{ with .Content }} {{ . }} {{ end }} {{ end }} {{ define "footer" }} <!-- --> {{ end }}
Docs Metapage Layout
{{ define "subheadline" }} <!-- --> {{ end }} {{ define "content" }} {{ $scratch := newScratch }} {{ ($scratch.Set "totalWordCount" 0) }} {{ ($scratch.Set "totalDrafts" 0) }} {{ ($scratch.Set "totalFinishedDocuments" 0) }} {{ ($scratch.Set "totalDocuments" 0) }} {{ with .Content }} {{ . }} {{ end }} {{ range where .Site.RegularPages "Type" "docs" }} {{ ($scratch.Set "totalWordCount" (add ($scratch.Get "totalWordCount") .WordCount)) }} {{ if .Draft }} {{ ($scratch.Set "totalDrafts" (add ($scratch.Get "totalDrafts") 1)) }} {{ else }} {{ ($scratch.Set "totalFinishedDocuments" (add ($scratch.Get "totalFinishedDocuments") 1)) }} {{ end }} {{ ($scratch.Set "totalDocuments" (add ($scratch.Get "totalDocuments") 1)) }} {{ end }} <p> At present, my website contains: </p> <ul> <li> {{ ($scratch.Get "totalFinishedDocuments") }} finished documents </li> <li> {{ ($scratch.Get "totalDrafts") }} drafts </li> </ul> <p> totalling {{ ($scratch.Get "totalDocuments") }} documents containing <strong> {{ ($scratch.Get "totalWordCount") }} </strong> words: </p> <ul> {{ range where .Site.RegularPages "Type" "docs" }} <li> <a href="{{ .Permalink}}"><strong> {{- if (eq .Kind "taxonomy") -}} {{- .Title | pluralize -}} {{- else -}}{{- .Title -}}{{- end -}} </strong></a><br/> </li> {{ end }} </ul> {{ end }} {{ define "footer" }} <!-- --> {{ end }}
Partial Layouts
In the context of Hugo, and thus my website, "partial layouts," or partials, are layouts which represent a discrete component of the page. If you're familiar with SMACSS, partials are equivalent to modules.
Brief Description Partial Layout
{{- if (in (.Site.Params.documentTypes) (.Layout | default .Type)) -}} {{ end }}
Description Partial Layout
This partial layout returns a paragraph about the page's metadata, based on its content type. An example of the return might be
<p> This <strong>essay</strong> is about <strong>Galavant</strong> and was <strong>released on October 11, 2018</strong>, has <strong>918 words</strong>, and is estimated to take <strong>4 minutes to read</strong>. </p>
Description Layout: Initialization
The top part of the description layout sets up which attributes should be shown in the description.
Attribute | Renders in… |
---|---|
List Count | |
Date | Essays, fictions, and notes |
Reading Time | Essays, fictions, letters, manuals, procedures, and singular procedures. |
Word Count | Essays, fictions, letters, manuals, procedures, and singular procedures. |
{{- $scratch := newScratch -}} {{- ($scratch.Set "showListItems" "") -}} {{- ($scratch.Set "showDate" "essay fiction note") -}} {{- ($scratch.Set "showReadingTime" "essay fiction letter manual procedure procedures") -}} {{- ($scratch.Set "showWordCount" "essay fiction letter manual procedure procedures") -}} {{- ($scratch.Set "paramTypes" slice) -}}
Description Layout: Determine Content Type
{{- if (isset .Params "categories") -}} {{- with .Params.categories -}} {{- range last 1 . -}} {{- ($scratch.Set "contentType" .) -}} {{- end -}} {{- end -}} {{- else -}} {{- $scratch.Set "contentType" "piece" -}} {{- end -}}
Description Layout: Determine Content Subject
{{- if (isset .Params "tags") -}} {{- with .Params.tags -}} {{- range last 1 . -}} {{- if (eq (. | title) .) -}} {{- ($scratch.Set "contentSubject" (. | humanize | title)) -}} {{- else -}} {{- ($scratch.Set "contentSubject" (. | humanize | lower)) -}} {{- end -}} {{- end -}} {{- end -}} {{- end -}}
Description Layout: Configure Grammar
{{- with ($scratch.Get "contentType") -}} {{- if (eq . ( . | pluralize)) -}} {{- ($scratch.SetInMap "grammar" "article" "these") -}} {{- ($scratch.SetInMap "grammar" "hasTense" "have") -}} {{- ($scratch.SetInMap "grammar" "isTense" "are") -}} {{- else -}} {{- ($scratch.SetInMap "grammar" "article" "this") -}} {{- ($scratch.SetInMap "grammar" "hasTense" "has") -}} {{- ($scratch.SetInMap "grammar" "isTense" "is") -}} {{- end -}} {{- end -}}
Description Layout: Configure Date
{{- if (in ($scratch.Get "showDate") ($scratch.Get "contentType")) -}} {{- with .Date -}} {{- ($scratch.SetInMap "pageParameters" "1date" .) -}} {{- end -}} {{- end -}}
Description Layout: Configure List Count
{{- if (in ($scratch.Get "showListItems") ($scratch.Get "contentType")) -}} {{- end -}}
Description Layout: Configure Word Count
{{- if (in ($scratch.Get "showWordCount") ($scratch.Get "contentType")) -}} {{- ($scratch.SetInMap "pageParameters" "3wordCount" .WordCount) -}} {{- end -}}
Description Layout: Configure Reading Time
{{- if (in ($scratch.Get "showReadingTime") ($scratch.Get "contentType")) -}} {{- ($scratch.SetInMap "pageParameters" "4readingTime" .ReadingTime) -}} {{- end -}}
Description Layout: Configure Draft
{{- if (.Draft) -}} {{- ($scratch.SetInMap "pageParameters" "5isDraft" true) -}} {{- end -}}
Description Layout: Build Intro Clause
With the variables assembled above, the layout now builds the actual
paragraph to be returned, inside the variable introClause
.
{{- ($scratch.Set "introClause" (printf "%s **%s**" ((index ($scratch.Get "grammar") "article") | title) ($scratch.Get "contentType"))) -}} {{- with ($scratch.Get "contentSubject") -}} {{- ($scratch.Set "introClause" (printf "%s is about **%s** and" ($scratch.Get "introClause") (printf "%s" .))) -}} {{- end -}} {{- range $k, $v := ($scratch.Get "pageParameters") -}} {{- ($scratch.Add "paramTypes" (slice $k)) -}} {{- end -}} {{- if (gt (len ($scratch.Get "paramTypes")) 1) -}} {{- ($scratch.Set "fullDesc" ($scratch.Get "introClause")) -}} {{- range first (sub (len ($scratch.Get "paramTypes")) 1) ($scratch.Get "paramTypes") -}} {{- if (eq . "1date") -}} {{- if $.PublishDate -}} {{- if (ne (string $.PublishDate) ("0001-01-01 00:00:00 +0000 UTC")) -}} {{- ($scratch.Set "fullDesc" (printf "%s was **released on %s**," ($scratch.Get "fullDesc") (dateFormat "January 2, 2006" $.PublishDate))) -}} {{- else -}} {{- ($scratch.Set "fullDesc" (printf "%s was **last updated on %s**," ($scratch.Get "fullDesc") (dateFormat "Jan 2, 2006" $.Date))) -}} {{- end -}} {{- end -}} {{- else if (eq . "2listItems") -}} {{- else if (eq . "3wordCount") -}} {{- ($scratch.Set "fullDesc" (printf "s% %s **%s words**," ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "hasTense") (string (index ($scratch.Get "pageParameters") .)))) | safeHTML -}} {{- else if (eq . "4readingTime") -}} {{- ($scratch.Set "fullDesc" (printf "%s %s estimated to take **%s minutes to read**," ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense") (string (math.Round (mul (index ($scratch.Get "pageParameters") .) 1.2))))) -}} {{- else if (eq . "5isDraft") -}} {{- ($scratch.Set "fullDesc" (printf "%s <strong>not finalized</strong>," ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense"))) -}} {{- end -}} {{- end -}} {{- range last 1 ($scratch.Get "paramTypes") -}} {{- if (eq . "1date") -}} {{- if $.PublishDate -}} {{- if (ne (string $.PublishDate) ("0001-01-01 00:00:00 +0000 UTC")) -}} {{- ($scratch.Set "fullDesc" (printf "%s was **released on %s**," ($scratch.Get "fullDesc") (dateFormat "January 2, 2006" $.PublishDate))) -}} {{- else -}} {{- ($scratch.Set "fullDesc" (printf "%s was **last updated on %s**," ($scratch.Get "fullDesc") (dateFormat "Jan 2, 2006" $.Date))) -}} {{- end -}} {{- end -}} {{- else if (eq . "2listItems") -}} {{- else if (eq . "3wordCount") -}} {{- ($scratch.Set "fullDesc" (printf "%s and %s **%s words**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "hasTense") (string (index ($scratch.Get "pageParameters") .)))) | safeHTML -}} {{- else if (eq . "4readingTime") -}} {{- ($scratch.Set "fullDesc" (printf "%s and %s estimated to take **%s minutes to read**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense") (string (math.Round (mul (index ($scratch.Get "pageParameters") .) 1.2))))) -}} {{- else if (eq . "5isDraft") -}} {{- ($scratch.Set "fullDesc" (printf "%s and %s **not finalized**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense"))) -}} {{- end -}} {{- end -}} {{- else if (gt (len ($scratch.Get "paramTypes")) 0) -}} {{- ($scratch.Set "fullDesc" ($scratch.Get "introClause")) -}} {{- with ($scratch.Get "contentSubject") -}} {{- ($scratch.Set "introClause" (printf "%s %s about %s and" ($scratch.Get "introClause") (index ($scratch.Get "grammar") "isTense") ($scratch.Get "contentSubject" ))) -}} {{- end -}} {{- range first 1 ($scratch.Get "paramTypes") -}} {{- if (eq . "1date") -}} {{- if $.PublishDate -}} {{- if (ne (string $.PublishDate) ("0001-01-01 00:00:00 +0000 UTC")) -}} {{- ($scratch.Set "fullDesc" (printf "%s was **released on %s**," ($scratch.Get "fullDesc") (dateFormat "January 2, 2006" $.PublishDate))) -}} {{- else -}} {{- ($scratch.Set "fullDesc" (printf "%s was **last updated on %s**," ($scratch.Get "fullDesc") (dateFormat "Jan 2, 2006" $.Date))) -}} {{- end -}} {{- end -}} {{- else if (eq . "2listItems") -}} {{- else if (eq . "3wordCount") -}} {{- ($scratch.Set "fullDesc" (printf "%s %s **%s words**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "hasTense") (string (index ($scratch.Get "pageParameters") .)))) -}} {{- else if (eq . "4readingTime") -}} {{- ($scratch.Set "fullDesc" (printf "%s %s estimated to take **%s minutes to read**." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense") (string (math.Round (mul (index ($scratch.Get "pageParameters") .) 1.2))))) -}} {{- else if (eq . "5isDraft") -}} {{- ($scratch.Set "fullDesc" (printf "%s %s <strong>not finalized</strong>." ($scratch.Get "fullDesc") (index ($scratch.Get "grammar") "isTense"))) -}} {{- end -}} {{- end -}} {{- else -}} {{- ($scratch.Set "fullDesc" ($scratch.Get "introClause")) -}} {{- end -}} {{- ($scratch.Get "fullDesc") | markdownify -}}
Header Navigation Partial Layout
{{ define "headerExtra" }} <nav> <ul> <li> <a href="/">Homepage</a> </li> <li> <a href="/docs/">Docs</a> </li> </ul> </nav> {{ end }}
Site Pages
The pages of my website come from three main sources:
- There are some basic pages that are written into this document and tangled out with the configution and layout. They're the sort of pages that are for information that doesn't exist outside my website - things like my contact page.
- There are also a few metapages written into the document that are used with specialized layout to provide information pages within the website - things like the list of drafts.
Basic Pages
Contact Page
+++ title = "Contact Me" type = "metapages" +++ _**In a hurry?**_ Send an email to my [public inbox](https://lists.sr.ht/~emsenn/public-inbox), or [send me an email](mailto:emsenn@emsenn.net) if you really have to. ## Introduction This website is just part of my online presence, and doesn't provide any means for readers to communicate back with me. I do maintain lots of other accounts for various purposes - this is a list of all them, not just the ones I use for "communicating." ## Email You can */send me an email/*. I maintain a [collection of mailing lists](https://lists.sr.ht/~emsenn/) relevant to my projects, as well as a [public inbox](https://lists.sr.ht/~emsenn/public-inbox) for more general public communication. I also accept [private emails](mailto:emsenn@emsenn.net) but I reserve the right to publicize anything you might send to me. ## Chatting I'm active in the Fediverse, a network of communication platforms: - At [@emsenn@mastodon.social](https://mastodon.social/@emsenn), I do my general chatting. _(If you're more familiar with legacy social media, it's kind of like my Twitter.)_ - At [@emsenn@tabletop.social](https://tabletop.social/@emsenn), I chat about tabletop role-playing games, like Dungeons and Dragons or my own _[Brave Old World](/projects/brave-old-world)_. ## Syndication In addition to publishing my non-commissioned writing on my website, I also syndicate on other platforms. - [@emsenn@wordsmith.social](https://wordsmith.social/emsenn) is where I syndicate drafts and non-commissioned writing. - [@emsenn@tabletop.press](https://tabletop.press/emsenn) is where I syndicate my tabletop gaming rules and adventures. - [LBRY](lbry://@emsenn) lets you buy my writing with a cryptocurrency of the same name. This website is also syndicated through the [DAT protocol](dat://beea87bd7ba3c55fbcf54a5f868dc5f6ff64b77ac8d82682170072c76a8d0c0f/) and [archived on the IPFS](https://neocities.org/site/emsenn/archives).
Contribute Page
Help Me Page
The help me page of my website is a list of things I currently want help with. I have plans to make this info available as json or something, as well, with the grand notion that if a few people do it, someone could write a client that pulls them in and gives you a sense of what your friends (or whoever) need help with - like an RSS for asking your social network for help. …Though that sounds rather impressive, and it's not my goal to personally develop this into more than making it easy for friends to see what I'm looking for help with.
Help Me Page Content
+++ title = "Help Me" layout = "helpMe" +++ This is a list of some things I want (volunteer) help with. If you have the answer, please send it to my [public inbox](https://lists.sr.ht/~emsenn/public-inbox). - I'd like to use Emacs as my email client. What's the best resource to read on how to do that?
Help Me Page Data
Services Page
My name is _**emsenn**_. I'm an independent consultant and writer who specializes in teaching senior executives how they can improve their business by adopting methods used in open-source software development.
Metapages
Documents Listing
Ending up at =emsenn.net/docs/~, this content is caught by Hugo and used as the basis for a special page that lists all the categories and tags that documents fall under.
+++ title = "My Documents" type = "metapages" layout = "docs" +++ This page is a listing of all the documents I've published to my website.
Drafts Listing
+++ title = "Drafts" author = ["emsenn"] lastmod = 2019-01-20T20:01:00-05:00 categories = ["webpage"] draft = false +++ This !!contentType!! is a listing of all the **_drafts_** in this website: documents that are, for one reason or another, not yet finished.
Finished Document Listing
+++ title = "Finished Documents" author = ["emsenn"] lastmod = 2019-01-20T20:01:00-05:00 categories = ["webpage"] draft = false +++ This !!contentType!! is a listing of all the **_finished documents_** in this website: documents that I consider complete and ready for general distribution. Note that this listing also includes webpages.
Project Pages
Brave Old World
+++ title = "Brave Old World" +++ _**Brave Old World**_ are rules for telling stories with friends: a collection of rules for playing a tabletop role-playing game.
Brutstrap
+++ title = "Brutstrap" +++ _**Brutstrap**_ is CSS for representing a HTML document's contents as it's constructed. The project is maintained at [git.sr.ht/~emsenn/brutstrap](https://git.sr.ht/~emsenn/brutstrap), and a demo is available at [emsenn.net/demos/brutstrap/](https://emsenn.net/demos/brutstrap/).
Data
Activities
2019-01-25 = """ I wrote a [Cultural Guide for Fediverse Newcomers](/docs/cultural-guide-for-fediverse-newcomers/) and released the [Oats](/projects/oats/) CSS theme.""" 2019-01-27 = """ I sent ["Hello, Parlour"](https://emsenn.net/docs/dear-parlour-hello-parlour) to my new [parlour mailing list](https://lists.sr.ht/~emsenn/parlour).""" 2019-01-28 = """ I sent ["Do We Need More Developers?"](https://emsenn.net/docs/dear-parlour-do-we-need-more-developers) to my [parlour mailing list](https://lists.sr.ht/~emsenn/parlour/)."""
Category Descriptions
directive = "_*Directives*_ are principles which guide my actions and decision-making." essay = "_*Essays*_ are short pieces written with some depth or seriousness." fiction = "_*Fictions*_ are untrue for one or more reason, usually entertainment." game = "_*Games*_ are rules for doing something fun, often with friends." letter = "_*Letters*_ are pieces written for a specific audience." list = "Lists of useful information." manual = "Guides for accomplishing a type of work or fulfilling a role." note = "Unrefined writing on a variety of topics." procedure = "A single set of instructions for completing an action. _These are singular procedures._" procedures = "A collection of procedures related to a broad action. _These are collections of procedures._" project = "Information about projects I'm developing." service = "Information about professional services I offer." webpage = "Other pages on this website; not really \"documents.\""
Index
introduction = """ I have an interest in the things that shape our interactions with technology, like software document and project governance.""" plans = [ "Finish centralizing my project repositories at [git.sr.ht/~emsenn](https://git.sr.ht/~emsenn).", "Consider using Org-mode to create a literately programmed static site generator.", "Develop a MUD engine." ]
Project Descriptions
brave-old-world = "Rules for telling stories with friends." brutstrap = "CSS rules for a brutalist website." oats = "CSS rules for a neutral brown brutalist website." website = "My website, a collection of literately-programmed and imported resources." fyreside = "A chatroom with a built-in card game." y-dwarf = "CSS rules for a cold blue brutalist website." teraum = "A hand-crafted satirical fantasy: stories and role-playing resources." you-are-conscious = "An interactive fiction: an artificial intelligence makes widgets." starhopper = "A multiplayer text-based game: race to find a new home for humanity." qtmud = "An engine for running a text-based multiplayer game."
404 Layout
{{- define "main" -}} <article> <h1 class="post-title">404</h1> <p> Sorry, we have misplaced that URL or it's pointing to something that doesn't exist. </p> <p> Head back <a href="/">Home</a> or use the <a href="/search/">Search</a> to try finding it again. </p> </article> {{- end -}}
Supplements
Contribute
This collection of Hugo templates was made possible with contributions from humans like you. Thank you! I currently accept contributions through the following platforms:
If there is another service through which you'd like to contribute, please send an email. Please note that in accordance with my personal directives #003 and #018, I release all useful information I create for free, so financial contributions do not entitle you to access to any "exclusive content."
Further Reading
- Hugo Documentation, to learn more about Hugo, a static site generator.
License
Copyright 2019 emsenn
Permission is hereby granted, free of charge, to any person obtaining a copy of this document and associated media files (the "Document"), to deal in the Doftware without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Doftware, and to permit persons to whom the Doftware is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The Document is provided "as is," without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, or noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort, or otherwise, arising from, out of or in connection with the Document or the use or other dealings in the Document.
Footnotes:
Document types are a concept I use in other parts of my work. See "Document Types" in my Writing Manual or "Document Types" in my Style Manual.