Skip to Content

Hugo Personal Website Theme

A Hugo theme by emsenn, last released on 2019-07-14, currently on version 0.1.0.

Table of Contents

Introduction

This Hugo theme is an implementation of a Hugo Theme for creating a personal website: a website catered around presenting information about a person. Hugo is a static site generator written in Go.

The theme is written primarily for my personal use, on https://emsenn.net.

My website contains information about me, a collection of my writing, and my various projects. My goal is to provide all that information with enough other information that folk can get a more holistic understanding of it.

This theme is in early development and poorly documented, but I have big aspirations for it.

This document was written by me, emsenn, in the United States. To the extent possible under law, I have waived all copyright and related or neighboring rights to this Hugo theme. This Hugo theme was created for the benefit of the public.

Hugo Personal Website Theme

Overview

This theme provides templates1 for generating a static website with the Hugo static site generator. It’s currently in-development, so the documentation, where present, is bad, and the code is even worse.

This is an ambitious theme: it currently is fed data from exported version of most of my source code and writing, in addition to some native content and data, and I have plans to pull in some remote data as well.

Operations

Install the Theme

Install with Git

Coming soon!

Install from Source

This theme’s source exists as an Org-mode document. The best way to work with it, then, is by editing that document, in Emacs. Then, you can use Babel to “tangle” the Hugo templates and such into their proper files. Edit the Org-mode file and then re-“tangle” the document to create fresh source files.

Theme Configuration

The configuration below tangles to ./build/theme.toml. Explaining it in detail is beyond the scope of this document, but if you’re changing this theme, you’ll probably wanna change this to reflect that. (Especially if you plan on sharing the theme; I don’t want to be receiving credit for your code!)

name = "Hugo Personal Website Theme"
license = "CC0"
[author]
  name = "emsenn"
  homepage = "https://emsenn.net"

Page Templates

This section contains the different page layouts.

HTML Page Templates

404 Page Layout

{{- define "main" -}}
<article>
    <h1>No Page at This Address</h1>
    <p>There is no page at this address: this is a <code>404</code> error. Below is an overview of this site's contents. You may also wish to use your browser's Back button to return to the previous page.
    </p>
    {{ partial "site-contents-listing.html" . }}
</article>

{{- end -}}
Basic Page Layout

Located at ./build/layouts/_default/baseof.html, this template serves as the base for the other HTML page templates.

This template, like a lot of them, relies heavily on partials and conditionals about what configuration or content your site has.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
{{- with .Site.Language.Lang }} xml:lang="{{- . -}}" lang="{{- . -}}"
{{- end }}>
<head>
{{ partial "head-meta.html" . }}
{{ partial "head-links.html" . }}
{{ partial "head-title.html" . }}
      <style>
      {{ partial "basic-css.css" . | safeCSS }}
      </style>
    </head>
    <body>
      <a class="skipToContentLink" href="#content">Skip to Content</a>
      <header>
       {{- block "header" . -}}
	<h1>{{- (printf "%s" (((.Data.Term | pluralize | humanize | title ) | default .Title)) | default "Personal Website") -}}</h1>
       {{- end -}}
      </header>
      <main>
	{{- block "main" . -}}
	  <!-- -->
	{{- end }}
      </main>
      <footer>
	{{- block "footer" . -}}
	  <!-- -->
	{{- end }}
      </footer>
    </body>
  </html>
Index Page Layout

{{ define "header" }}
{{ if ($.Site.Params.familyName | default $.Site.Params.givenName) }}
  {{ (printf "<h1>My name is %s.</h1>" (partial "who-am-i.html" .)) | safeHTML }}
{{ else }}
<h1>{{ (.Title | default $.Site.Title) }}</h1>
{{ end }}
{{ end }}
{{ define "main" }}
{{ with .Content }}<section>{{ . }}</section>{{ else }}
<section>
<p>
{{ partial "maker-brief.html" . }}
{{ partial "site-contents-brief.html" . }}
</p>
<p>
Recently, I {{ partial "recent-activities-brief.html" $.Site.Data.personalData.activities }}.
</p>
<p>
Currently, I'm {{ partial "plans-brief.html" $.Site.Data.personalData.plans.current }}.
</p>
<p>
Soon, I want to {{ partial "plans-brief.html" $.Site.Data.personalData.plans.soon }}.
</p>
</section>
{{ end }}
{{ if (eq $.Site.Params.showHCard true) }}
What follows is my "<code>h-card</code>": a collection of personal information that is here to help computers and humans learn more about me.
  {{ partial "h-card.html" . }}
{{ end }}
{{ end }}
List Page Layout

Located at ./build/layouts/_default/list.html, this layout serves serves as the base for pages that exist to serve lists, like the index (homepage), or taxonomical list pages, such as those for categories or tags.

{{ define "main" }}
  {{ with .Content }}{{ . }}{{ end }}
  {{ partial "pages-listing" . }}
{{ end }}
Single Page Layout

{{- define "main" -}}
  {{ with .Content }}
    {{ . }}
  {{ end }}
  {{ if (eq .Type "essays") }}
    <h3>Editorial and License Information</h3>
    My name is emsenn and I wrote this essay for the benefit of the commons. To the extent possible under law, I have waived all copyright and related or neighboring rights to it. If you're viewing it on a remote server, you're encouraged to download your own copy. Essays like this are made possible with <a href="/support/">financial support</a> from readers like you. Thank you. To read more of my work and to learn more about me, visit <a href="https://emsenn.net">https://emsenn.net</a>
  {{ end }}
{{- end -}}
Webring Layouts
Writers of the Fediverse Webring
{{- define "main" -}}
  {{ with .Content }}
    {{ . }}
  {{ end }}
  {{ $ring := getJSON "http://ring.acdw.net/members" }}
  {{ with $ring }}<ul>{{ range $ring }}
    <li><a href="{{ .href }}">{{ .name }}</a>: {{ .desc }}
      {{ with .fedi }}
	Follow them at <a href="{{ . }}">{{ . }}</a>.
      {{ end }}</li>{{ end }}</ul>{{ end }}
{{- end -}}
Unique Pages
Now Page
{{ define "main" }}
<p>My name is {{ partial "who-am-i.html" . }}. {{ partial "maker-brief.html" . }}</p>
<p>
Here's some of what I'm working on now:
</p>
{{ partial "plans-listing.html" $.Site.Data.personalData.plans.current }}
<p>
Here's what I plan to do soon:
{{ partial "plans-listing.html" $.Site.Data.personalData.plans.current }}
</p>
{{ end }}

Partial Templates

HTML Partial Templates

Basic CSS
body {
position: relative;
background-color: #eee;
color: #444;
font-family: serif;
margin: 0 auto;
padding-bottom: 6rem;
min-height: 100%;
font-size: 1.2em;
}
header, h1 {
font-family: sans-serif;
text-align: left;
margin-left: 1em;
width: 80vw;
overflow: hidden;
font-family: sans-serif;
}
.title { font-size: 3.2rem; }
.subtitle { font-size: 2.2rem; }
main, #content {
width: 75vw;
max-width: 40em;
margin: 0 0 0 2em;
line-height: 1.6;
margin-bottom: 8rem;
}
footer, #postamble {
padding: 1em 0;
position: absolute;
right: 0;
bottom: 0;
left: 0;
}
section {
border-bottom: 0.1em solid #444;
margin-bottom: 1em;
}
.outline-3 {
border-bottom: 0.1rem dotted #444;
}
blockquote {
padding: 0.5rem;
border-left: 0.1em solid #444;
}
table {
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
border: 0.1em solid #444;
}
thead { font-family: sans-serif; }
th, td {
padding: 0 0.3em;
border: 0.01em solid #444;
}
img {
max-width: 80vw;
vertical-align: middle;
}
pre, .src {
padding: 0.5em;
border: 0.1em solid #444;
white-space: pre-wrap;
overflow-x: scroll;
text-overflow: clip;
}
dt {
font-weight: normal;
display: inline-block;
border-bottom: 0.1rem dotted #444;
}
#text-index dt { border-bottom: none; }
h2, h3, h4, h5, h6, h7, h8, h9, h10 {
display: block;
font-family: sans-serif;
margin: 0.5em;
}
h2 {
text-align: center;
}
h2 { font-size: 2em; }
h3 {
font-size: 1.8em;
}
h4 {
font-size: 1.6em;
}
h5 {
font-size: 1.4em;
margin: 0.5em 0 0.2em 10%;
}
h6 {
font-size: 1.2em;
margin: 0.5em 0 0.2em 30%;
}
a {
text-decoration: none;
color: #3ac;
display: inline;
position: relative;
border-bottom: 0.1rem dotted;
line-height: 1.2;
transition: border 0.3s;
}
a:hover {
color: #5ce;
outline-style: none;
border-bottom: 0.1rem solid;
}
a:visited { color: #b8c; }
a:visited:hover { color: #dae; }
a:focus {
outline-style: none;
border-bottom: 0.1rem solid;
}
::selection { background-color: #777; color: #eee; }
a::selection { background-color: #ccc; }
.todo {
background-color: #ddd;
color: #333;
font-size: .8rem;
float: right;
}
.org-src-container + .example {
margin-left: 8em;
}
label.org-src-name {
margin: 0 0 0 3em;
font-family: sans-serif;
font-size: 1rem;
line-height: 0;
}
.skipToContentLink {
opacity: 0;
position: absolute;
}
.skipToContentLink:focus{
opacity:1
}
Essay Brief
<a href="{{- .Permalink -}}">{{- .Title -}}</a> is a {{ .FuzzyWordCount -}}-word essay
{{- with .Date }} released on {{ (dateFormat "January 2, 2006" .) -}}{{- end -}}
{{- with .Params.tags }} about {{ range . -}}{{- . | humanize | lower -}}{{- end -}}{{- end -}}.
H-card

This partial template is for generating an h-card, a sort of online “business card.” To verify that your h-card is functioning, IndieWeb have provided a validator: https://indiewebify.me/validate-h-card/

This template

<section class="vcard h-card">
<details><summary>Naming</summary>
  Proper Name: <span class="p-name">{{ $.Site.Params.properName }}</span>
  {{ if (or $.Site.Params.givenName $.Site.Params.familyName) }}
  <table>
    <thead><tr>
      {{ with $.Site.Params.honorificPrefix }}<th>Honorific</th>{{ end }}
      {{ with $.Site.Params.givenName }}<th>Given Name</th>{{ end }}
      {{ with $.Site.Params.familyName }}<th>Family Name</th>{{ end }}
    </tr></thead>
    <tbody><tr>
      {{ with $.Site.Params.honorificPrefix }}<td>{{ . }}</td>{{ end }}
      {{ with $.Site.Params.givenName }}<td>{{ . }}</td>{{ end }}
      {{ with $.Site.Params.familyName }}<td>{{ . }}</td>{{ end }}
    </tr></tbody>
  </table>
  {{ end }}
</details>
<details><summary>Images</summary>
  {{ with $.Site.Params.logo }}
    <dt>Logo</dt>
    <dd><img style="max-width: 3em;" class="u-logo" src="{{ . }}"
	  {{ with $.Site.Params.logoAlt }}
	    alt="{{ . }}"
	  {{ end }}></dd>
  {{ end }}
  {{ with $.Site.Params.photo }}
    <dt>Photo</dt>
    <dd><img style="max-width: 4em;" class="u-photo" src="{{ . }}"
	  {{ with $.Site.Params.photoAlt }}
	    alt="{{ . }}"
	  {{ end }}></dd>
  {{ end }}
</details>
{{ if (or $.Site.Params.canonicalURL $.Site.Params.phoneNumber) }}
<details><summary>Contact Methods</summary>
<dl>
{{ with $.Site.Params.canonicalURL }}
<dt>Homepage</dt><dd><a class="u-url u-uid" rel="me" href="{{ .}}">{{ . }}</dd>
{{ end }}
{{ with $.Site.Params.email }}
<dt>Email</dt><dd><a class="u-email" href="mailto:{{ .}}">{{ . }}</dd>
{{ end }}
</dl>
</details>
{{ end }}
<details class="adr">
<summary>Physical Location</summary>
	<span class="locality">Chapel Hill</span>,
	<span class="region">North Carolina</span>,
	<span class="country-name">United States of America</span>
      </details>
      </p>
  </section>

NOTE: The domain is hardcoded into the webmentions here because I’m sleepy.

<link href="https://gmpg.org/xfn/11" rel="profile">
{{- with .Params.Email }}
<link href="mailto:{{- . -}}" rel="me authn">
{{- end -}}
{{- if .Params.Webmentions }}
<link rel="webmention" href="https://webmention.io/emsenn.net/webmention" />
<link rel="pingback" href="https://webmention.io/webmention?forward=https://emsenn.net/webmention" />
{{ end }}
Head Meta
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
<meta name="referrer" content="no-referrer">
{{- with .Params.description }}
<meta name="description" content="{{ . }}">
{{- end -}}
{{- with .Params.keywords }}
<meta name="keywords" content="{{- .Render "keywords" -}}">
{{- end -}}
{{- with (.Params.author | default (.Site.Author)) }}
<meta name="author" content="{{ delimit .  ", " }}">
{{- end }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:locale" content="{{ .Site.Language.Lang }}">
<meta property="og:site_name" content="{{ .Site.Title }}">
{{- with .Title }}
<meta property="og:title=" content="{{ . }}">
{{- end -}}
{{- with .Params.Description }}
<meta property="og:description" content="{{ . }}">
{{- end }}
Head Title
<title>{{- (printf "%s" (((.Data.Term | pluralize | humanize | title ) | default .Title)) | default ("Personal Website")) -}}</title>

Index Menu Listing
{{ with .Site.Menus.index }}
  <ul>
    {{ range . }}
      <li><a href="{{ .URL }}">{{ .Name }}</a></li>
    {{ end }}
  </ul>
{{ end }}
Maker Brief
{{- with $.Site.Params.makeThings -}}
I {{ $.Site.Params.makeVerb | default "make" }}
{{ if (eq (len .) 1) }}
{{- . -}}
{{- else if (eq (len .) 2) }}
{{- delimit . " and " -}}
{{- else }}
{{- delimit . ", " ", and " -}}
{{- end -}}
{{- with $.Site.Params.makeFocus }}
with a focus on {{ . }}
{{- end -}}
.
{{- end -}}
Pages Listing
    {{ with .Pages }}
      <ul>
	{{ range sort . "Title" "asc" }}
	  <li>

	      {{- if (eq .Kind "taxonomy") -}}
	   <a href="{{ .Permalink}}"><strong>
     {{- .Title | pluralize -}}</strong></a>
	      {{ else if (eq .Type "essays")  }}
		{{ partial "essay-brief" . }}
	      {{ else }}
<a href="{{ .Permalink}}"><strong>
		{{- .Title -}}</strong></a>
	      {{- end -}}
	  </strong></a><br/>
	</li>
      {{ end }}
    </ul>
  {{ end }}
Recent Activities Listing
{{ $scratch := newScratch }}
    {{ with .Site.Data.personalData.activities }}
      <h2>My Recent Activites</h2>
      <ul>
	{{ range $date, $report := . }}
	  {{ $scratch.Add "activityDates" (slice $date) }}
	{{ end }}
	{{ range (sort ($scratch.Get "activityDates") "value" "desc") }}
	    <li>
	      {{ (printf "**%s**" (dateFormat "January 2, 2006" .)) | markdownify -}}
	      {{- with (index $.Site.Data.personalData.activities .) -}}
		{{- if (eq (len .) 1) -}}
		  {{- (printf ": %s" (markdownify (index . 0)) | safeHTML) -}}
		{{- else -}}
		  <ul>
		    {{ range . }}
		      <li>{{ . | safeHTML | markdownify }}</li>
		    {{ end }}
		  </ul>
		{{ end }}
	      {{ end }}
	    </li>
	{{ end }}
      </ul>
    {{ end }}
Recent Activities Brief
{{- $scratch := newScratch -}}
{{- range sort . "value" "desc" -}}{{- range . }}
  {{- $scratch.Add "activities" (slice ( . | markdownify)) -}}
{{- end -}}{{- end -}}
{{- with ($scratch.Get "activities") -}}
{{- if (eq (len .) 0) -}}{{- else -}}
  {{- if (eq (len .) 1) }}
      {{ . }}
    {{- else if (eq (len .) 2) }}
      {{ delimit . " and " }}
    {{- else }}
      {{ delimit (first 3 .) ", " ", and " }}
    {{- end -}}
  {{- end -}}
{{- end -}}
Plans Brief
{{- $scratch := newScratch -}}
{{- range . -}}
  {{- $scratch.Add "plans" (slice ( . | markdownify )) -}}
{{- end -}}
{{- with ($scratch.Get "plans") -}}
{{- if (eq (len .) 0) -}}{{- else -}}
  {{- if (eq (len .) 1) }}
      {{ . }}
    {{- else if (eq (len .) 2) }}
      {{ delimit . " and " }}
    {{- else }}
      {{ delimit (first 3 .) ", " ", and " }}
    {{- end -}}
  {{- end -}}
{{- end -}}
Plans Listing
{{- $scratch := newScratch -}}
{{- range . -}}
  {{- $scratch.Add "plans" (slice ( . | markdownify )) -}}
{{- end -}}
{{- with ($scratch.Get "plans") -}}
{{- if (eq (len .) 0) -}}{{- else -}}
<ul>
{{- range first 3 . -}}
<li>{{ . }}</li>
{{- end -}}
</ul>
{{- end -}}{{- end -}}
Section Count
{{- $sectionCount := (len (where .Site.RegularPages "Type" .Section)) -}}
{{- $sectionCount }} <a href="{{ .Section }}/">{{- if (eq $sectionCount 1) -}}{{- .Section | humanize | lower | singularize -}}{{- else -}}{{- .Section | humanize | lower -}}{{- end -}}</a>{{- printf "" -}}

Why does this end in an empty printf statement? Otherwise the template returns ending in a newline and that’d need to be stripped away every time!

Site Contents Brief
{{- $scratch := newScratch -}}
{{- range where $.Site.RegularPages ".File.TranslationBaseName" "in" $.Site.Params.mainPages -}}
  {{- $scratch.Add "mainPagePhrases" (slice (printf "<a href=\"%s\">%s</a>" .Permalink .Params.mainPhrase)) -}}
{{- end -}}
{{- $mPP := ($scratch.Get "mainPagePhrases") -}}
{{- range $.Site.Params.mainSections -}}
  {{ if (eq (len (where $.Site.RegularPages "Type" .)) 0) }}{{ else }}
  {{- $scratch.Add "mainSectionCounts" (slice (partial "section-count.html" (dict "Section" . "Site" $.Site))) -}}
  {{ end }}
{{- end -}}
{{- $mS := ($scratch.Get "mainSectionCounts") -}}

{{- if (eq (len $mPP) 0) -}}
{{- else -}}
This website has pages to
{{- if (eq (len $mPP) 1) }}
{{ (index $mPP 0) }}
{{- else if (eq (len $mPP) 2) }}
{{ delimit $mPP " and " }}
{{- else }}
{{ delimit $mPP ", " ", and " }}
{{- end -}}
.
{{- end -}}

{{- if (eq (len $mS) 0) }}
{{- else }}
It also contains
{{- if (eq (len $mS) 1) }}
{{ (index $mS 0) }}
{{- else if (eq (len $mS) 2) }}
{{ delimit $mS " and " }}
{{- else }}
{{ delimit $mS ", " ", and " }}
{{- end -}}
.
{{- end -}}
Site Contents Listing
{{- $scratch := newScratch -}}
{{- range where $.Site.RegularPages ".File.TranslationBaseName" "in" $.Site.Params.mainPages -}}
  {{- $scratch.Add "mainPagePhrases" (slice ((printf "<a href=\"%s\">%s</a>" .Permalink .Params.indexPhrase) | safeHTML)) -}}
{{- end -}}
{{- $mPP := ($scratch.Get "mainPagePhrases") -}}
{{- range $.Site.Params.mainSections -}}
  {{ if (eq (len (where $.Site.RegularPages "Type" .)) 0) }}{{ else }}
  {{- $scratch.Add "mainSectionCounts" (slice (partial "section-count.html" (dict "Section" . "Site" $.Site))) -}}
  {{ end }}
{{- end -}}
{{- $mS := ($scratch.Get "mainSectionCounts") -}}



{{- if (eq (len $mPP) 0) -}}
{{- else -}}
<ul>
{{- range $mPP -}}<li><a href="{{ . }}">{{ . }}</a></li>{{ end }}
</ul>
{{ end }}

{{- if (eq (len $mS) 0) }}
{{- else }}
<ul>
{{- range $mS -}}<li><a href="{{ . }}">{{ . }}</a></li>{{ end }}
</ul>
{{ end }}
Total Word Count
{{ $scratch := newScratch }}
{{ range $.Site.RegularPages }}{{ $scratch.Add "totalWordCount" .WordCount }}{{ end }}
{{ $scratch.Get "totalWordCount" }}
Webmention Feed
{{ $mentions := getJSON (add "https://webmention.io/api/mentions.jf2?target=" .Permalink) }}
{{ $mentions.name | default "Webmentionssss" }}
{{ with $mentions.children }}
<ul>{{ range . }}
<li>{{ . }}</li>
{{ end }}{{ end }}
Who Am I
{{- with $.Site.Params.givenName -}}
{{- (printf "<span class=\"given-name\">%s</span>" .) | safeHTML -}}
{{- end -}}
{{- with $.Site.Params.familyName -}}
{{- (printf "<span class=\"family-name\">%s</span>" .) | safeHTML -}}
{{- end -}}

Supplements

Index

JSON :

HTML :

Markdown :

Hugo :

README

This Hugo theme is an implementation of a Hugo Theme for creating a personal website: a website catered around presenting information about a person. Hugo is a static site generator written in Go.

The theme is written primarily for my personal use, on https://emsenn.net.

My website contains information about me, a collection of my writing, and my various projects. My goal is to provide all that information with enough other information that folk can get a more holistic understanding of it.

This theme is in early development and poorly documented, but I have big aspirations for it.

This document was written by me, emsenn, in the United States. To the extent possible under law, I have waived all copyright and related or neighboring rights to this Hugo theme. This Hugo theme was created for the benefit of the public.

Source

The following is the source of this document as it was written by the author.

#+TITLE: Hugo Personal Website Theme
#+AUTHOR: emsenn
#+DATE: 2019-07-14
#+EXPORT_FILE_NAME: ./hugo-personal-website-theme
#+HUGO_BASE_DIR: ~/src/personal-website/
#+HUGO_SECTION: computer-instruction-sets
#+MACRO: document-type Hugo theme
#+MACRO: version 0.1.0
A {{{doc}}} by {{{author}}}, last released on {{{date}}}, currently on version {{{version}}}.
#+TOC: headlines 2
* Introduction
  :PROPERTIES:
  :CUSTOM_ID: introduction
  :END:
This {{{doc}}} is an implementation of a Hugo Theme for creating a /personal website/: a website catered around presenting information about a person. Hugo is a static site generator written in Go.

The theme is written primarily for my personal use, on [[https://emsenn.net][https://emsenn.net]].

My website contains information about me, a collection of my writing, and my various projects. My goal is to provide all that information with enough other information that folk can get a more holistic understanding of it.

This theme is in early development and poorly documented, but I have big aspirations for it.

{{{document-eli(default)}}}
* Hugo Personal Website Theme
  :PROPERTIES:
  :CUSTOM_ID: hugo-media-package-channel-generator
  :header-args: :padline no
  :END:
#+TOC: headlines 1 local
** DRAFT Overview
This theme provides templates[fn:1] for generating a static website with the Hugo static site generator. It's currently in-development, so the documentation, where present, is bad, and the code is even worse.

This is an ambitious theme: it currently is fed data from exported version of most of my source code and writing, in addition to some native content and data, and I have plans to pull in some remote data as well.
** DRAFT Operations
#+TOC: headlines 1 local
*** Install the Theme
**** Install with Git
*/Coming soon!/*
**** Install from Source
This theme's source exists as an /Org-mode/ document. The best way to work with it, then, is by editing that document, in /Emacs/. Then, you can use Babel to "tangle" the Hugo templates and such into their proper files. Edit the /Org-mode/ file and then re-"tangle" the document to create fresh source files.
** DRAFT Theme Configuration
The configuration below /tangles/ to =./build/theme.toml=. Explaining
it in detail is beyond the scope of this document, but if you're changing this theme, you'll probably wanna change this to reflect that. (Especially if you plan on sharing the theme; I don't want to be receiving credit for your code!)
#+begin_src toml :tangle ./theme.toml
  name = "Hugo Personal Website Theme"
  license = "CC0"
  [author]
    name = "emsenn"
    homepage = "https://emsenn.net"
#+end_src
** DRAFT Page Templates
This section contains the different page /layouts/.
#+TOC: headlines 1 local
*** HTML Page Templates
#+toc: headlines 1 local
**** DRAFT 404 Page Layout
#+NAME: 404-layout
#+BEGIN_SRC html :tangle ./layouts/404.html
{{- define "main" -}}
<article>
    <h1>No Page at This Address</h1>
    <p>There is no page at this address: this is a <code>404</code> error. Below is an overview of this site's contents. You may also wish to use your browser's Back button to return to the previous page.
    </p>
    {{ partial "site-contents-listing.html" . }}
</article>

{{- end -}}
#+END_SRC
**** Basic Page Layout
Located at =./build/layouts/_default/baseof.html=, this template serves as the base for the other HTML page templates.

This template, like a lot of them, relies heavily on partials and conditionals about what configuration or content your site has.

#+BEGIN_SRC html :tangle ./layouts/_default/baseof.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
{{- with .Site.Language.Lang }} xml:lang="{{- . -}}" lang="{{- . -}}"
{{- end }}>
<head>
{{ partial "head-meta.html" . }}
{{ partial "head-links.html" . }}
{{ partial "head-title.html" . }}
      <style>
      {{ partial "basic-css.css" . | safeCSS }}
      </style>
    </head>
    <body>
      <a class="skipToContentLink" href="#content">Skip to Content</a>
      <header>
       {{- block "header" . -}}
	<h1>{{- (printf "%s" (((.Data.Term | pluralize | humanize | title ) | default .Title)) | default "Personal Website") -}}</h1>
       {{- end -}}
      </header>
      <main>
	{{- block "main" . -}}
	  <!-- -->
	{{- end }}
      </main>
      <footer>
	{{- block "footer" . -}}
	  <!-- -->
	{{- end }}
      </footer>
    </body>
  </html>
#+end_src
**** DRAFT Index Page Layout
#+NAME: index-layout
#+BEGIN_SRC html :tangle ./layouts/_default/index.html
  {{ define "header" }}
  {{ if ($.Site.Params.familyName | default $.Site.Params.givenName) }}
    {{ (printf "<h1>My name is %s.</h1>" (partial "who-am-i.html" .)) | safeHTML }}
  {{ else }}
  <h1>{{ (.Title | default $.Site.Title) }}</h1>
  {{ end }}
  {{ end }}
  {{ define "main" }}
  {{ with .Content }}<section>{{ . }}</section>{{ else }}
  <section>
  <p>
  {{ partial "maker-brief.html" . }}
  {{ partial "site-contents-brief.html" . }}
  </p>
  <p>
  Recently, I {{ partial "recent-activities-brief.html" $.Site.Data.personalData.activities }}.
  </p>
  <p>
  Currently, I'm {{ partial "plans-brief.html" $.Site.Data.personalData.plans.current }}.
  </p>
  <p>
  Soon, I want to {{ partial "plans-brief.html" $.Site.Data.personalData.plans.soon }}.
  </p>
  </section>
  {{ end }}
  {{ if (eq $.Site.Params.showHCard true) }}
  What follows is my "<code>h-card</code>": a collection of personal information that is here to help computers and humans learn more about me.
    {{ partial "h-card.html" . }}
  {{ end }}
  {{ end }}
#+END_SRC
**** DRAFT List Page Layout
Located at =./build/layouts/_default/list.html=, this /layout/ serves
serves as the base for pages that exist to serve lists, like the index
(homepage), or taxonomical list pages, such as those for categories or
tags.
#+BEGIN_SRC html :tangle ./layouts/_default/list.html
  {{ define "main" }}
    {{ with .Content }}{{ . }}{{ end }}
    {{ partial "pages-listing" . }}
  {{ end }}
#+END_SRC
**** DRAFT Single Page Layout
#+NAME: default-single-document-layout
#+BEGIN_SRC html :tangle ./layouts/_default/single.html
  {{- define "main" -}}
    {{ with .Content }}
      {{ . }}
    {{ end }}
    {{ if (eq .Type "essays") }}
      <h3>Editorial and License Information</h3>
      My name is emsenn and I wrote this essay for the benefit of the commons. To the extent possible under law, I have waived all copyright and related or neighboring rights to it. If you're viewing it on a remote server, you're encouraged to download your own copy. Essays like this are made possible with <a href="/support/">financial support</a> from readers like you. Thank you. To read more of my work and to learn more about me, visit <a href="https://emsenn.net">https://emsenn.net</a>
    {{ end }}
  {{- end -}}
#+END_SRC
**** DRAFT Webring Layouts
***** DRAFT Writers of the Fediverse Webring
#+BEGIN_SRC html :tangle ./layouts/_default/writers-of-the-fediverse-webring.html
  {{- define "main" -}}
    {{ with .Content }}
      {{ . }}
    {{ end }}
    {{ $ring := getJSON "http://ring.acdw.net/members" }}
    {{ with $ring }}<ul>{{ range $ring }}
      <li><a href="{{ .href }}">{{ .name }}</a>: {{ .desc }}
	{{ with .fedi }}
	  Follow them at <a href="{{ . }}">{{ . }}</a>.
	{{ end }}</li>{{ end }}</ul>{{ end }}
  {{- end -}}
#+END_SRC
**** Unique Pages
***** Now Page
#+begin_src html :tangle ./layouts/_default/now.html
{{ define "main" }}
<p>My name is {{ partial "who-am-i.html" . }}. {{ partial "maker-brief.html" . }}</p>
<p>
Here's some of what I'm working on now:
</p>
{{ partial "plans-listing.html" $.Site.Data.personalData.plans.current }}
<p>
Here's what I plan to do soon:
{{ partial "plans-listing.html" $.Site.Data.personalData.plans.current }}
</p>
{{ end }}
#+end_src
** Partial Templates
#+toc: headlines 1 local
*** HTML Partial Templates
#+toc: headlines 1 local
**** Basic CSS
#+begin_src css :tangle ./layouts/partials/basic-css.css
body {
position: relative;
background-color: #eee;
color: #444;
font-family: serif;
margin: 0 auto;
padding-bottom: 6rem;
min-height: 100%;
font-size: 1.2em;
}
header, h1 {
font-family: sans-serif;
text-align: left;
margin-left: 1em;
width: 80vw;
overflow: hidden;
font-family: sans-serif;
}
.title { font-size: 3.2rem; }
.subtitle { font-size: 2.2rem; }
main, #content {
width: 75vw;
max-width: 40em;
margin: 0 0 0 2em;
line-height: 1.6;
margin-bottom: 8rem;
}
footer, #postamble {
padding: 1em 0;
position: absolute;
right: 0;
bottom: 0;
left: 0;
}
section {
border-bottom: 0.1em solid #444;
margin-bottom: 1em;
}
.outline-3 {
border-bottom: 0.1rem dotted #444;
}
blockquote {
padding: 0.5rem;
border-left: 0.1em solid #444;
}
table {
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
border: 0.1em solid #444;
}
thead { font-family: sans-serif; }
th, td {
padding: 0 0.3em;
border: 0.01em solid #444;
}
img {
max-width: 80vw;
vertical-align: middle;
}
pre, .src {
padding: 0.5em;
border: 0.1em solid #444;
white-space: pre-wrap;
overflow-x: scroll;
text-overflow: clip;
}
dt {
font-weight: normal;
display: inline-block;
border-bottom: 0.1rem dotted #444;
}
#text-index dt { border-bottom: none; }
h2, h3, h4, h5, h6, h7, h8, h9, h10 {
display: block;
font-family: sans-serif;
margin: 0.5em;
}
h2 {
text-align: center;
}
h2 { font-size: 2em; }
h3 {
font-size: 1.8em;
}
h4 {
font-size: 1.6em;
}
h5 {
font-size: 1.4em;
margin: 0.5em 0 0.2em 10%;
}
h6 {
font-size: 1.2em;
margin: 0.5em 0 0.2em 30%;
}
a {
text-decoration: none;
color: #3ac;
display: inline;
position: relative;
border-bottom: 0.1rem dotted;
line-height: 1.2;
transition: border 0.3s;
}
a:hover {
color: #5ce;
outline-style: none;
border-bottom: 0.1rem solid;
}
a:visited { color: #b8c; }
a:visited:hover { color: #dae; }
a:focus {
outline-style: none;
border-bottom: 0.1rem solid;
}
::selection { background-color: #777; color: #eee; }
a::selection { background-color: #ccc; }
.todo {
background-color: #ddd;
color: #333;
font-size: .8rem;
float: right;
}
.org-src-container + .example {
margin-left: 8em;
}
label.org-src-name {
margin: 0 0 0 3em;
font-family: sans-serif;
font-size: 1rem;
line-height: 0;
}
.skipToContentLink {
opacity: 0;
position: absolute;
}
.skipToContentLink:focus{
opacity:1
}
#+end_src
**** Essay Brief
#+begin_src html :tangle ./layouts/partials/essay-brief.html
<a href="{{- .Permalink -}}">{{- .Title -}}</a> is a {{ .FuzzyWordCount -}}-word essay
{{- with .Date }} released on {{ (dateFormat "January 2, 2006" .) -}}{{- end -}}
{{- with .Params.tags }} about {{ range . -}}{{- . | humanize | lower -}}{{- end -}}{{- end -}}.
#+end_src
**** DRAFT H-card
This /partial template/ is for generating an /h-card/, a sort of online "business card." To verify that your /h-card/ is functioning, IndieWeb have provided a validator: [[https://indiewebify.me/validate-h-card/][https://indiewebify.me/validate-h-card/]]

This /template/
#+begin_src html :tangle ./layouts/partials/h-card.html
<section class="vcard h-card">
<details><summary>Naming</summary>
  Proper Name: <span class="p-name">{{ $.Site.Params.properName }}</span>
  {{ if (or $.Site.Params.givenName $.Site.Params.familyName) }}
  <table>
    <thead><tr>
      {{ with $.Site.Params.honorificPrefix }}<th>Honorific</th>{{ end }}
      {{ with $.Site.Params.givenName }}<th>Given Name</th>{{ end }}
      {{ with $.Site.Params.familyName }}<th>Family Name</th>{{ end }}
    </tr></thead>
    <tbody><tr>
      {{ with $.Site.Params.honorificPrefix }}<td>{{ . }}</td>{{ end }}
      {{ with $.Site.Params.givenName }}<td>{{ . }}</td>{{ end }}
      {{ with $.Site.Params.familyName }}<td>{{ . }}</td>{{ end }}
    </tr></tbody>
  </table>
  {{ end }}
</details>
<details><summary>Images</summary>
  {{ with $.Site.Params.logo }}
    <dt>Logo</dt>
    <dd><img style="max-width: 3em;" class="u-logo" src="{{ . }}"
	  {{ with $.Site.Params.logoAlt }}
	    alt="{{ . }}"
	  {{ end }}></dd>
  {{ end }}
  {{ with $.Site.Params.photo }}
    <dt>Photo</dt>
    <dd><img style="max-width: 4em;" class="u-photo" src="{{ . }}"
	  {{ with $.Site.Params.photoAlt }}
	    alt="{{ . }}"
	  {{ end }}></dd>
  {{ end }}
</details>
{{ if (or $.Site.Params.canonicalURL $.Site.Params.phoneNumber) }}
<details><summary>Contact Methods</summary>
<dl>
{{ with $.Site.Params.canonicalURL }}
<dt>Homepage</dt><dd><a class="u-url u-uid" rel="me" href="{{ .}}">{{ . }}</dd>
{{ end }}
{{ with $.Site.Params.email }}
<dt>Email</dt><dd><a class="u-email" href="mailto:{{ .}}">{{ . }}</dd>
{{ end }}
</dl>
</details>
{{ end }}
<details class="adr">
<summary>Physical Location</summary>
	<span class="locality">Chapel Hill</span>,
	<span class="region">North Carolina</span>,
	<span class="country-name">United States of America</span>
      </details>
      </p>
  </section>
#+end_src
**** DRAFT Head Links
*/NOTE:/* The domain is hardcoded into the webmentions here because I'm sleepy.
#+begin_src html :tangle ./layouts/partials/head-links.html
<link href="https://gmpg.org/xfn/11" rel="profile">
{{- with .Params.Email }}
<link href="mailto:{{- . -}}" rel="me authn">
{{- end -}}
{{- if .Params.Webmentions }}
<link rel="webmention" href="https://webmention.io/emsenn.net/webmention" />
<link rel="pingback" href="https://webmention.io/webmention?forward=https://emsenn.net/webmention" />
{{ end }}
#+end_src
**** Head Meta
#+begin_src html :tangle ./layouts/partials/head-meta.html
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
<meta name="referrer" content="no-referrer">
{{- with .Params.description }}
<meta name="description" content="{{ . }}">
{{- end -}}
{{- with .Params.keywords }}
<meta name="keywords" content="{{- .Render "keywords" -}}">
{{- end -}}
{{- with (.Params.author | default (.Site.Author)) }}
<meta name="author" content="{{ delimit .  ", " }}">
{{- end }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:locale" content="{{ .Site.Language.Lang }}">
<meta property="og:site_name" content="{{ .Site.Title }}">
{{- with .Title }}
<meta property="og:title=" content="{{ . }}">
{{- end -}}
{{- with .Params.Description }}
<meta property="og:description" content="{{ . }}">
{{- end }}
#+end_src
**** Head Title
#+begin_src html :tangle ./layouts/partials/head-title.html
<title>{{- (printf "%s" (((.Data.Term | pluralize | humanize | title ) | default .Title)) | default ("Personal Website")) -}}</title>

#+end_src
**** Index Menu Listing
#+begin_src html :tangle ./layouts/partials/index-menu-listing.html
  {{ with .Site.Menus.index }}
    <ul>
      {{ range . }}
	<li><a href="{{ .URL }}">{{ .Name }}</a></li>
      {{ end }}
    </ul>
  {{ end }}
#+end_src
**** Maker Brief
#+begin_src html :tangle ./layouts/partials/maker-brief.html
{{- with $.Site.Params.makeThings -}}
I {{ $.Site.Params.makeVerb | default "make" }}
{{ if (eq (len .) 1) }}
{{- . -}}
{{- else if (eq (len .) 2) }}
{{- delimit . " and " -}}
{{- else }}
{{- delimit . ", " ", and " -}}
{{- end -}}
{{- with $.Site.Params.makeFocus }}
with a focus on {{ . }}
{{- end -}}
.
{{- end -}}
#+end_src
**** Pages Listing
#+begin_src html :tangle ./layouts/partials/pages-listing.html
    {{ with .Pages }}
      <ul>
	{{ range sort . "Title" "asc" }}
	  <li>

	      {{- if (eq .Kind "taxonomy") -}}
	   <a href="{{ .Permalink}}"><strong>
     {{- .Title | pluralize -}}</strong></a>
	      {{ else if (eq .Type "essays")  }}
		{{ partial "essay-brief" . }}
	      {{ else }}
<a href="{{ .Permalink}}"><strong>
		{{- .Title -}}</strong></a>
	      {{- end -}}
	  </strong></a><br/>
	</li>
      {{ end }}
    </ul>
  {{ end }}
#+end_src
**** Recent Activities Listing
#+begin_src html :tangle ./layouts/partials/recent-activities-listing.html
{{ $scratch := newScratch }}
    {{ with .Site.Data.personalData.activities }}
      <h2>My Recent Activites</h2>
      <ul>
	{{ range $date, $report := . }}
	  {{ $scratch.Add "activityDates" (slice $date) }}
	{{ end }}
	{{ range (sort ($scratch.Get "activityDates") "value" "desc") }}
	    <li>
	      {{ (printf "**%s**" (dateFormat "January 2, 2006" .)) | markdownify -}}
	      {{- with (index $.Site.Data.personalData.activities .) -}}
		{{- if (eq (len .) 1) -}}
		  {{- (printf ": %s" (markdownify (index . 0)) | safeHTML) -}}
		{{- else -}}
		  <ul>
		    {{ range . }}
		      <li>{{ . | safeHTML | markdownify }}</li>
		    {{ end }}
		  </ul>
		{{ end }}
	      {{ end }}
	    </li>
	{{ end }}
      </ul>
    {{ end }}
#+end_src
**** Recent Activities Brief
#+begin_src html :tangle ./layouts/partials/recent-activities-brief.html
{{- $scratch := newScratch -}}
{{- range sort . "value" "desc" -}}{{- range . }}
  {{- $scratch.Add "activities" (slice ( . | markdownify)) -}}
{{- end -}}{{- end -}}
{{- with ($scratch.Get "activities") -}}
{{- if (eq (len .) 0) -}}{{- else -}}
  {{- if (eq (len .) 1) }}
      {{ . }}
    {{- else if (eq (len .) 2) }}
      {{ delimit . " and " }}
    {{- else }}
      {{ delimit (first 3 .) ", " ", and " }}
    {{- end -}}
  {{- end -}}
{{- end -}}
#+end_src
**** Plans Brief
#+begin_src html :tangle ./layouts/partials/plans-brief.html
{{- $scratch := newScratch -}}
{{- range . -}}
  {{- $scratch.Add "plans" (slice ( . | markdownify )) -}}
{{- end -}}
{{- with ($scratch.Get "plans") -}}
{{- if (eq (len .) 0) -}}{{- else -}}
  {{- if (eq (len .) 1) }}
      {{ . }}
    {{- else if (eq (len .) 2) }}
      {{ delimit . " and " }}
    {{- else }}
      {{ delimit (first 3 .) ", " ", and " }}
    {{- end -}}
  {{- end -}}
{{- end -}}
#+end_src

**** Plans Listing
#+begin_src html :tangle ./layouts/partials/plans-listing.html
{{- $scratch := newScratch -}}
{{- range . -}}
  {{- $scratch.Add "plans" (slice ( . | markdownify )) -}}
{{- end -}}
{{- with ($scratch.Get "plans") -}}
{{- if (eq (len .) 0) -}}{{- else -}}
<ul>
{{- range first 3 . -}}
<li>{{ . }}</li>
{{- end -}}
</ul>
{{- end -}}{{- end -}}
#+end_src
**** DRAFT Section Count
#+begin_src html :tangle ./layouts/partials/section-count.html :padlines no
{{- $sectionCount := (len (where .Site.RegularPages "Type" .Section)) -}}
{{- $sectionCount }} <a href="{{ .Section }}/">{{- if (eq $sectionCount 1) -}}{{- .Section | humanize | lower | singularize -}}{{- else -}}{{- .Section | humanize | lower -}}{{- end -}}</a>{{- printf "" -}}
#+end_src

Why does this end in an empty printf statement? Otherwise the template returns ending in a newline and that'd need to be stripped away every time!

**** DRAFT Site Contents Brief
#+begin_src html :tangle ./layouts/partials/site-contents-brief.html
  {{- $scratch := newScratch -}}
  {{- range where $.Site.RegularPages ".File.TranslationBaseName" "in" $.Site.Params.mainPages -}}
    {{- $scratch.Add "mainPagePhrases" (slice (printf "<a href=\"%s\">%s</a>" .Permalink .Params.mainPhrase)) -}}
  {{- end -}}
  {{- $mPP := ($scratch.Get "mainPagePhrases") -}}
  {{- range $.Site.Params.mainSections -}}
    {{ if (eq (len (where $.Site.RegularPages "Type" .)) 0) }}{{ else }}
    {{- $scratch.Add "mainSectionCounts" (slice (partial "section-count.html" (dict "Section" . "Site" $.Site))) -}}
    {{ end }}
  {{- end -}}
  {{- $mS := ($scratch.Get "mainSectionCounts") -}}

  {{- if (eq (len $mPP) 0) -}}
  {{- else -}}
  This website has pages to
  {{- if (eq (len $mPP) 1) }}
  {{ (index $mPP 0) }}
  {{- else if (eq (len $mPP) 2) }}
  {{ delimit $mPP " and " }}
  {{- else }}
  {{ delimit $mPP ", " ", and " }}
  {{- end -}}
  .
  {{- end -}}

  {{- if (eq (len $mS) 0) }}
  {{- else }}
  It also contains
  {{- if (eq (len $mS) 1) }}
  {{ (index $mS 0) }}
  {{- else if (eq (len $mS) 2) }}
  {{ delimit $mS " and " }}
  {{- else }}
  {{ delimit $mS ", " ", and " }}
  {{- end -}}
  .
  {{- end -}}
#+end_src
**** DRAFT Site Contents Listing
#+begin_src html :tangle ./layouts/partials/site-contents-listing.html
  {{- $scratch := newScratch -}}
  {{- range where $.Site.RegularPages ".File.TranslationBaseName" "in" $.Site.Params.mainPages -}}
    {{- $scratch.Add "mainPagePhrases" (slice ((printf "<a href=\"%s\">%s</a>" .Permalink .Params.indexPhrase) | safeHTML)) -}}
  {{- end -}}
  {{- $mPP := ($scratch.Get "mainPagePhrases") -}}
  {{- range $.Site.Params.mainSections -}}
    {{ if (eq (len (where $.Site.RegularPages "Type" .)) 0) }}{{ else }}
    {{- $scratch.Add "mainSectionCounts" (slice (partial "section-count.html" (dict "Section" . "Site" $.Site))) -}}
    {{ end }}
  {{- end -}}
  {{- $mS := ($scratch.Get "mainSectionCounts") -}}



  {{- if (eq (len $mPP) 0) -}}
  {{- else -}}
  <ul>
  {{- range $mPP -}}<li><a href="{{ . }}">{{ . }}</a></li>{{ end }}
  </ul>
  {{ end }}

  {{- if (eq (len $mS) 0) }}
  {{- else }}
  <ul>
  {{- range $mS -}}<li><a href="{{ . }}">{{ . }}</a></li>{{ end }}
  </ul>
  {{ end }}
#+end_src
**** Total Word Count
#+begin_src html :tangle ./layouts/partials/total-word-count.html
{{ $scratch := newScratch }}
{{ range $.Site.RegularPages }}{{ $scratch.Add "totalWordCount" .WordCount }}{{ end }}
{{ $scratch.Get "totalWordCount" }}
#+end_src
**** Webmention Feed
#+begin_src html :tangle ./layouts/partials/webmention-feed.html
{{ $mentions := getJSON (add "https://webmention.io/api/mentions.jf2?target=" .Permalink) }}
{{ $mentions.name | default "Webmentionssss" }}
{{ with $mentions.children }}
<ul>{{ range . }}
<li>{{ . }}</li>
{{ end }}{{ end }}
#+end_src
**** Who Am I
#+begin_src html :tangle ./layouts/partials/who-am-i.html
{{- with $.Site.Params.givenName -}}
{{- (printf "<span class=\"given-name\">%s</span>" .) | safeHTML -}}
{{- end -}}
{{- with $.Site.Params.familyName -}}
{{- (printf "<span class=\"family-name\">%s</span>" .) | safeHTML -}}
{{- end -}}
#+end_src
* Supplements
#+TOC: headlines 1 local
** Index
- JSON ::
- HTML ::
- Markdown ::
- Hugo ::
** README
   :PROPERTIES:
   :EXPORT_FILE_NAME: ./README
   :END:
#+INCLUDE: "./source.org::#introduction" :only-contents t
** Source
The following is the source of this document as it was written by the
author.
#+INCLUDE:  "./source.org" src org

* Footnotes

[fn:1] Hugo's documentation seems to use /layout/ and /template/ interchangeably, or there's a logic to it I've never understood. I will be using the word /template/ throughout.

  1. Hugo’s documentation seems to use layout and template interchangeably, or there’s a logic to it I’ve never understood. I will be using the word template throughout. [return]