Hugo Website
Table of Contents
Introduction
This collection of Hugo templates is unfinished, and I have no plans to finish it.
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. Please direct comments to my public inbox or, if necessary, my personal email.
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 Website
Operations
Installation
Preparing the System
mkdir ../build/personal-website/layouts/{_default,docs,}
Tangling the Code
Building the Site
Publishing
Hugo Configuration & Layouts
Hugo Configuration
Hugo is the static site generator I use, and while most of the configuration comes from individual documents, there is some site-wide configuration applied.
This configuration is written to the ./config.toml
file.
Base URL Configuration
The baseURL
variable, accessed through .Site.BaseURL
, is currently
unused.
baseURL = "https://emsenn.net"
Language Configuration
The languageCode
variable, accessed through .Site.Language.Lang
,
is used in the Base Default Layout.
languageCode = "en-us"
Emoji Configuration
The enableEmoji
variables sets whether or not emoticon shortcodes in
documents are rendered. (:smile: to a smiling face emoji, for example.)
enableEmoji = true
Title Configuration
title = "emsenn"
Site Author Configuration
author = "emsenn"
Site Document Types Configuration
[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, blocks are equivalent to layouts.
Default Layouts
The default layouts, located under ./layouts/_default/
are used
when there's not a more relevant layout to use with a document.
Because Hugo is written as a static website generator, all the default
templates are in HTML.
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.
{{ block "documentDeclaration" . }} <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" {{- with .Site.Language.Lang }} xml:lang="{{- . -}}" lang="{{- . -}}" {{- end }}> {{ end }}
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 }}
{{ 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 }}
</html>
{{ 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 }}
{{ define "subheadline" }} <!-- --> {{ end }} {{ define "content" }} {{ with .Content }} {{ . }} {{ end }} {{ end }}
{{- 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 }}
<time>
tag for datetime content.Content Layouts
Document Layouts
{{ 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 }}
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 }}
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
{{ define "style" }} <link rel="stylesheet" type="text/css" href="./projects/brutstrap/brutstrap.css"> {{ end }}
Metapage Layouts
{{ define "subheadline" }} {{ with .Description }} <p> {{ . }} </p> {{ end }} {{ end }} {{ define "content" }} {{ with .Content }} {{ . }} {{ end }} {{ end }} {{ define "footer" }} <!-- --> {{ end }}
{{ 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.
{{- if (in (.Site.Params.documentTypes) (.Layout | default .Type)) -}} {{ end }}
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>
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) -}}
{{- if (isset .Params "categories") -}} {{- with .Params.categories -}} {{- range last 1 . -}} {{- ($scratch.Set "contentType" .) -}} {{- end -}} {{- end -}} {{- else -}} {{- $scratch.Set "contentType" "piece" -}} {{- end -}}
{{- 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 -}}
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 -}}
{{ define "headerExtra" }} <nav> <ul> <li> <a href="/">Homepage</a> </li> <li> <a href="/docs/">Docs</a> </li> </ul> </nav> {{ end }}
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 -}}
Basic Pages
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."
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."
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.