~gpanders/gpanders.com

1a3494af98158671defe43ad5f21bb58ea688bda — Gregory Anders 1 year, 11 months ago 7abab8e
Redesign and simplify site
D .gitmodules => .gitmodules +0 -3
@@ 1,3 0,0 @@
[submodule "themes/hugo-flex"]
	path = themes/hugo-flex
	url = https://github.com/de-souza/hugo-flex.git

M LICENSE => LICENSE +1 -1
@@ 1,4 1,4 @@
Source code in this repository is licensed as follows:
Source code for this website and any code contained within is licensed as follows:

    MIT License


M README.md => README.md +4 -0
@@ 1,3 1,7 @@
Source code for [gpanders.com][].

[gpanders.com]: https://gpanders.com

## License

[MIT](https://choosealicense.com/licenses/mit/)

M assets/css/base.tpl.css => assets/css/base.tpl.css +87 -181
@@ 22,22 22,43 @@
  }
}

* {
  box-sizing: border-box;
}

/* This ensures the width of the viewport remains the same with or without
 * scrollbars */
html {
  width: 100vw;
  overflow-x: hidden;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
  line-height: 1.5;
  margin: 0;
  padding: 0;
  margin: auto;
  padding: 2rem;
  background: var(--main-bg-color);
  color: var(--main-fg-color);
  display: grid;
  grid: "sidebar content" "footer footer" / 20ch auto;
  grid-gap: 2rem;
  max-width: {{ site.Params.width }};
}

@media only screen and (max-width: 800px) {
  body {
    grid: "sidebar" "content" "footer" / auto;
  }
}

main {
  margin: auto;
  display: grid;
  grid-template-columns: auto;
  grid-auto-columns: 20rem;
  grid-gap: 2em;
  max-width: {{ site.Params.width }};
  grid-area: content;
  overflow: auto;
}

aside > *, article > * {
  margin-top: 0;
}

a {


@@ 108,260 129,145 @@ th, td {
  overflow: visible;
}

nav {
  border-bottom: 1px solid var(--border-color);
}

.Banner {
  display: grid;
  margin: auto;
  max-width: {{ site.Params.width }};
  line-height: 2;
  text-align: center;
article > h1 {
  line-height: 1;
}

.Banner-menu {
  list-style: none;
  display: grid;
  align-items: baseline;
  margin: 0;
  padding: 0;
  grid-row: 2;
.p-name {
  font-weight: bold;
}

.Banner-title {
  grid-row: 1;
.heading {
  margin: 0;
}

.Banner-item {
  grid-row: 1;
}

.Banner-link {
  color: var(--strong-color);
  padding: 0.5rem 1rem;
}

.Banner-search {
  grid-row: 2;
  grid-column: 1 / {{ len site.Menus.nav | add 1 }};
}

@media only screen and (min-width: 600px) {
  .Banner {
    grid-template-columns: 1fr auto;
    text-align: left;
  }

  .Banner-menu {
    grid-row: 1;
  }

  .Banner-search {
    grid-row: 1;
  }
}

.Content {
  padding: 1em;
  overflow: auto;
.heading ~ .heading {
  margin-top: 1em;
}

.Heading {
  margin-bottom: 0;
.heading > a {
  color: var(--main-fg-color);
}

.Subheading {
.subheading {
  font-size: 14px;
  color: var(--subtle-color);
  margin: 0;
}

.Tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin: 1.5rem 0;
  padding: 0;
}

.Tags-item {
.tags-item {
  border-radius: 0.2rem;
  margin: 0.2rem;
  padding: 0 0.3rem;
}

.Tags-link {
.tags-link {
  color: var(--link-color);
}

.Pagination {
  border: none;
  display: grid;
  justify-content: space-between;
  margin-top: 2em;
.sidebar {
  grid-area: sidebar;
}

.Pagination a {
  font-size: 1rem;
}

.Pagination a[rel="prev"] {
  grid-column: 1;
}

.Pagination a[rel="next"] {
  grid-column: 2;
}

.Home-posts {
  padding-right: 2em;
}

.Sidebar {
  padding: 1em;
  border-top: 1px solid var(--border-color);
}

.Sidebar ul {
.sidebar ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.Sidebar li {
.sidebar li {
  margin: 1.25em 0;
}

@media only screen and (min-width: 800px) {
  .Sidebar {
    border-top: 0;
    margin: 0;
    grid-column: 2;
.sidebar a {
  color: var(--main-fg-color);
}

@media only screen and (max-width: 800px) {
  .sidebar {
    border-bottom: 1px solid var(--border-color);
    text-align: center;
  }
}

.Footer {
footer {
  grid-area: footer;
  text-align: center;
  margin: 0;
  padding: 1em;
  color: var(--subtle-color);
  border-top: 1px solid var(--border-color);
}

.Project-list {
  margin: 0;
}

.Project-list dt {
  font-weight: 500;
  margin-top: 1em;
}

.Project-list a {
  color: var(--main-fg-color);
}

.Project-list dd {
  font-size: 0.8rem;
.lastmod {
  color: var(--subtle-color);
  margin: 0;
}

.List-header {
  border-bottom: 1px solid var(--border-color);
}

.List {
  list-style: none;
  padding: 0;
}

.List-item {
  margin: 2em 0;
}

.List-link {
  margin: 0;
}

.List-link a {
  color: var(--main-fg-color);
}

.Lastmod {
  font-size: 14px;
  color: var(--subtle-color);
  text-align: center;
  margin: 2em 0 1em;
}

.Lastmod a {
.lastmod a {
  color: var(--subtle-color);
}

.Search-form {
  padding: 0.5rem 1rem;
.search-form {
  padding: 0;
  display: flex;
  position: relative;
  min-width: 15rem;
}

.Search-input {
@media only screen and (max-width: 800px) {
  .search-form {
    justify-content: center;
  }
}

.search-input input {
  border-radius: 5px;
  border: 1px solid var(--border-color);
  padding: 0 0.5em;
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.8;
  width: 100%;
  box-sizing: border-box;
  background: var(--search-bg-color);
  color: var(--main-fg-color);
}

.Search-input:focus {
.search-input input:focus {
  border-color: var(--link-color);
  box-shadow: 0 0 2px var(--link-color);
}

.Search-icon {
  position: absolute;
  right: 1.5em;
  top: 0.5em;
  cursor: pointer;
}

.Search-icon svg {
  fill: #ccc;
  vertical-align: text-bottom;
.search-icon {
  display: flex;
  align-items: center;
}

.Search-icon input {
  display: none;
.search-icon input {
  margin-left: -2em;
}

.Search-results {
  display: none;
.search-results {
  display: flex;
  flex-direction: column;
  list-style: none;
  padding: 0;
  position: absolute;
  top: 2em;
  border: 1px solid var(--border-color);
  border-radius: 0.25em;
  width: calc(100% - 2rem - 2px);
  background: var(--search-bg-color);
}

@media only screen and (min-width: 800px) {
  .Search-results {
    width: 300px;
@media only screen and (max-width: 800px) {
  .search-results {
    max-width: 100%;
  }
}

.Search-results li {
.search-results li {
  padding: 0.5em;
  margin: 0;
  font-size: 14px;
  border-top: 1px solid var(--border-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;


@@ 369,15 275,15 @@ nav {
  text-align: left;
}

.Search-results li:first-of-type {
  border-top: none;
.search-results li + li {
  border-top: 1px solid var(--border-color);
}

.Search-results li.selected {
.search-results li.selected {
  background: var(--link-color);
  color: var(--main-bg-color);
}

.Search-results li a {
.search-results li a {
  color: inherit;
}

M assets/js/search.tpl.js => assets/js/search.tpl.js +16 -16
@@ 32,11 32,11 @@

{{ $searchData := resources.Get "js/search-data.tpl.js" | resources.ExecuteAsTemplate "js/search-data.js" . | minify | fingerprint }}

(function() {
  const icon = document.querySelector('.Search-icon');
  const form = document.querySelector('.Search-form');
  const input = document.querySelector('.Search-input');
  const results = document.querySelector('.Search-results');
(() => {
  const icon = document.querySelector('.search-icon > input');
  const form = document.querySelector('.search-form');
  const input = document.querySelector('.search-input > input');
  const results = document.querySelector('.search-results');

  if (!form || !input || !results) {
    return


@@ 45,22 45,22 @@
  // The search icon acts as the submit button when Javascript is not enabled.
  // However, when Javascript *is* enabled form submission is disabled in favor
  // of selecting one of the search items directly. In order to avoid
  // confusion, remove the 'cursor: pointer' style directive on the icon.
  icon.style.cursor = 'auto';
  // confusion, set the cursor style to 'default'.
  icon.style.cursor = 'default';

  let timer = undefined;
  form.addEventListener('submit', submit);
  form.addEventListener('keydown', navigate);
  form.addEventListener('blur', function() {
    timer = setTimeout(function() { clearResults(); }, 20);
  form.addEventListener('blur', () => {
    timer = setTimeout(() => clearResults(), 20);
  }, true);
  form.addEventListener('focus', function() { if (timer) clearTimeout(timer); }, true);
  form.addEventListener('focus', () => { if (timer) clearTimeout(timer); }, true);

  input.addEventListener('focus', init);
  input.addEventListener('keyup', search);

  // Close search results on escape
  document.addEventListener('keyup', function(e) { if (e.keyCode === {{ $KEY_ESC }}) clearResults(); });
  document.addEventListener('keyup', e => { if (e.keyCode === {{ $KEY_ESC }}) clearResults(); });

  function init() {
    input.removeEventListener('focus', init); // init once


@@ 79,7 79,7 @@
    while (results.firstChild) {
      results.removeChild(results.firstChild);
    }
    results.style.display = '';
    results.style.display = 'none';
  }

  function submit(event) {


@@ 151,12 151,12 @@
      return;
    }

    window.searchIndex.search(input.value, 10, function(hits) {
      hits.forEach(function(hit) {
    window.searchIndex.search(input.value, 10, hits => {
      hits.forEach(hit => {
        let li = createResultItem(hit);
        results.appendChild(li);
      });
      results.style.display = 'block';
      results.style.display = '';
    });
  }



@@ 169,7 169,7 @@
    li.addEventListener('focus', select);
    li.addEventListener('mouseleave', deselect);
    li.addEventListener('click', submit);
    li.addEventListener('keyup', function(e) { if (e.keyCode === {{ $KEY_RETURN }}) submit(e); });
    li.addEventListener('keyup', e => { if (e.keyCode === {{ $KEY_RETURN }}) submit(e); });

    a.tabIndex = -1;
    a.href = page.href;

M config.toml => config.toml +11 -4
@@ 2,7 2,6 @@ baseURL = "https://gpanders.com/"
languageCode = "en-us"
author = "Gregory Anders"
title = "g.p. anders"
theme = "hugo-flex"
enableGitInfo = true
pluralizeListTitles = false
pygmentsUseClasses = true


@@ 10,18 9,26 @@ pygmentsUseClasses = true
[taxonomies]

[params]
  opengraph = true
  css = ["css/syntax/light.css", "css/syntax/dark.css"]
  description = "Personal website for Gregory Anders"
  footer = 'Content on this site is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a> license.'
  width = "65rem"

[[menu.nav]]
  name = "Blog"
  url = "/blog"
  url = "/"
  weight = 1

[[menu.nav]]
  name = "Notes"
  url = "https://notes.gpanders.com"
  weight = 2

[[menu.nav]]
  name = "Projects"
  url = "/projects"
  weight = 3

[[menu.nav]]
  name = "About"
  url = "/about"
  weight = 4

A content/about/index.md => content/about/index.md +30 -0
@@ 0,0 1,30 @@
---
title: About
type: about
---

Hi, I'm Gregory. I worked as a technology consultant in Dallas doing full-stack
web development before getting a Master's Degree in Aerospace Engineering from
the University of Texas. While at UT, I worked in the [Radionavigation
Lab][rnl] where we developed autonomous navigation for micro UAVs. I now do
low-level electronics and embedded work for flight systems.

In my free time, I like to work on free and open source software. You can read
about a few of [my own projects][projects] or check out my profile on
[GitHub][github] or [Sourcehut][sourcehut].

This site is built with Hugo. It is [open source][source], ad-free, and
tracker-free. If you'd like to show your support or appreciation for my work,
you can [buy me a coffee][ko-fi]!

Please feel free to reach me at
[contact@gpanders.com](mailto:contact@gpanders.com) with any comments or
questions ([PGP][]).

[source]: https://git.sr.ht/~gpanders/gpanders.com
[ko-fi]: https://ko-fi.com/gpanders
[rnl]: https://rnl.ae.utexas.edu/
[projects]: /projects
[sourcehut]: https://sr.ht/~gpanders
[github]: https://github.com/gpanders
[PGP]: /publickey.txt

M content/blog/books-for-beginner-economists.md => content/blog/books-for-beginner-economists.md +4 -4
@@ 43,7 43,7 @@ Check out these books from your local library or use the links above to buy
them on Amazon. If you do read any of these books, I'd love to [hear what you
think!](mailto:contact@gpanders.com).

[Naked Economics]: https://amzn.to/3ahxQbU
[Undercover Economist]: https://amzn.to/2xnRshj
[Thinking Fast]: https://amzn.to/2Kc3U6k
[Nudge]: https://amzn.to/2Ve0TZG
[Naked Economics]: https://www.amazon.com/Naked-Economics-Undressing-Dismal-Science/dp/0393356493
[Undercover Economist]: https://www.penguinrandomhouse.com/books/75341/the-undercover-economist-by-tim-harford/
[Thinking Fast]: https://www.amazon.com/Thinking-Fast-Slow-Daniel-Kahneman/dp/0374533555
[Nudge]: https://www.amazon.com/Nudge-Improving-Decisions-Health-Happiness/dp/014311526X

M content/projects/ijq.md => content/projects/ijq.md +12 -0
@@ 4,3 4,15 @@ summary: Interactive jq
href: https://sr.ht/~gpanders/ijq/
featured: true
---

`ijq` is a command-line utility that provides an interactive interface to `jq`,
the JSON processing tool. It provides a two pane TUI and an input field: as you
write your `jq` query into the input field the JSON is processed in real time
and lets you preview the result of your query interactively. `ijq` works in
pipelines allowing it to be a near drop-in replacement for `jq`: when you close
`ijq` the filtered JSON is written to `stdout` which allows you to consume it
later in the pipeline.

Check out [a demo][asciicast]!

[asciicast]: https://asciinema.org/a/396956

M content/projects/meta-scipy.md => content/projects/meta-scipy.md +3 -0
@@ 4,3 4,6 @@ summary: OpenEmbedded layer for Scipy
href: https://github.com/gpanders/meta-scipy
featured: true
---

This layer brings [scipy](https://scipy.org) into the OpenEmbedded build
ecosystem.

M content/projects/pushbroom.md => content/projects/pushbroom.md +4 -0
@@ 4,3 4,7 @@ summary: Sweep your filesystem clear of clutter
href: https://sr.ht/~gpanders/pushbroom
featured: true
---

`pushbroom` is a simple script that automatically removes old files from
specified directories which helps keep folders clear of clutter. I wrote about
the evolution of `pushbroom` [here]({{<relref "/blog/make-your-mac-clean-itself" >}}).

M content/projects/vim-medieval.md => content/projects/vim-medieval.md +6 -0
@@ 4,3 4,9 @@ summary: Evaluate Markdown code blocks within Vim
href: https://github.com/gpanders/vim-medieval
featured: true
---

`vim-medieval` is a Vim plugin that enables you to evaluate code blocks in
Markdown buffers. The result of these evaluations can be written to other code
blocks within your document or to a file on your filesystem. Code blocks can
be combined together, allowing you to do a primitive style of literate
programming in Vim.

M content/projects/vim-oldfiles.md => content/projects/vim-oldfiles.md +8 -0
@@ 4,3 4,11 @@ summary: Improve Vim's native recent file history
href: https://github.com/gpanders/vim-oldfiles
featured: true
---

`vim-oldfiles` is a simple Vim plugin in the spirit of [Tim Pope's Vim
plugins][tpope] that aims to enhance native Vim functionality in a way that
fits into the Vim paradigm. It improves Vim's built-in `:oldfiles` command by
leveraging Vim's quickfix list and by updating the oldfiles list while the Vim
session is active.

[tpope]: https://github.com/tpope/

M content/projects/wk.md => content/projects/wk.md +11 -0
@@ 4,3 4,14 @@ summary: Command line tool to manage a personal wiki
href: https://git.sr.ht/~gpanders/wk
featured: true
---

`wk` is a simple command line tool inspired by the Zettelkasten note-taking
system for managing a personal wiki or collection of notes.

This program has undergone multiple rewrites: it serves as my test program for
experimenting in different languages. Over the course of its life, it has been
written in bash, Python, Zig, and Nim.

This is the tool I use to manage my own [collection of notes][notes].

[notes]: https://notes.gpanders.com

M layouts/_default/baseof.html => layouts/_default/baseof.html +9 -12
@@ 3,24 3,21 @@

<head>
  {{ partial "meta.html" . }}
  {{ partial "title.html" . }}
  <title>
    {{- if eq .Title site.Title -}}
      {{ .Title }}
    {{- else -}}
      {{ with .Title }}{{ . }} | {{ end }}{{ site.Title }}
    {{- end -}}
  </title>
  {{ partial "link.html" . }}
  {{ partial "load_site_assets.html" . }}
  {{ block "load_page_assets" . }}
    {{ with .Content }}{{ end }}
  {{ end }}
  {{ partial "assets.html" . }}
</head>

<body>
  {{ partialCached "banner.html" . }}
  {{ partialCached "sidebar.html" . }}
  <main>
    <section class="Content">
      {{ block "main" . }}{{ end }}
    </section>
    {{ if ne .Kind "section" }}
      {{ partialCached "sidebar.html" . }}
    {{ end }}
    {{ block "main" . }}{{ end }}
  </main>
  {{ partialCached "footer.html" . }}
</body>

A layouts/_default/list.html => layouts/_default/list.html +8 -0
@@ 0,0 1,8 @@
{{ define "main" }}

{{ range where site.RegularPages "Section" "blog" }}
<p class="heading p-name"><a class="u-url u-uid" href="{{ .RelPermalink }}" rel="bookmark">{{ .Title }}</a></p>
{{ partial "subheading.html" . }}
{{ end }}

{{ end }}

A layouts/about/single.html => layouts/about/single.html +9 -0
@@ 0,0 1,9 @@
{{ define "main" }}

<article class="h-entry">
  <div class="e-content">
    {{ .Content }}
  </div>
</article>

{{ end }}

D layouts/blog/list.html => layouts/blog/list.html +0 -19
@@ 1,19 0,0 @@
{{ define "main" }}

{{ partial "heading.html" . }}
{{ .Content }}
{{ range .Pages.GroupByPublishDate "2006" }}
<h2 class="List-header">{{ .Key }}</h2>
<ul class="List">
  {{ range .Pages }}
  <li class="List-item">
    <h3 class="List-link"><a href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
    {{ with .PublishDate | default nil }}
    <time datetime="{{ .Format "2006-01-02T00:00:00Z00:00" }}">{{ .Format "January 2, 2006" }}</time>
    {{ end }}
  </li>
  {{ end }}
</ul>
{{ end }}

{{ end }}

M layouts/blog/single.html => layouts/blog/single.html +4 -3
@@ 1,12 1,13 @@
{{ define "main" }}

<article class="h-entry">
  {{ partial "heading.html" . }}
  <h1 class="heading p-name"><a class="u-url u-uid" href="{{ .RelPermalink }}" rel="bookmark">{{ .Title }}</a></h1>
  {{ partial "subheading.html" . }}
  <div class="e-content">
  {{ .Content }}
    {{ .Content }}
  </div>
  {{ with .GitInfo }}
  <p class="Lastmod">Last modified by <a class="p-author h-card" href="{{ "" | absURL }}">{{ .AuthorName }}</a> on <time class="dt-updated" datetime="{{ .AuthorDate.Format "2006-01-02T00:00:00Z00:00" }}">{{ .AuthorDate.Format "January 2, 2006" }}</time></p>
  <p class="lastmod"><a href="https://git.sr.ht/~gpanders/gpanders.com/commit/{{ .Hash }}">Last modified on <time class="dt-updated" datetime="{{ .AuthorDate.Format "2006-01-02T00:00:00Z00:00" }}">{{ .AuthorDate.Format "January 2, 2006" }}</time></a></p>
  {{ end }}
</article>


D layouts/index.html => layouts/index.html +0 -43
@@ 1,43 0,0 @@
{{ define "load_page_assets" }}

  {{ $pages := where .Site.RegularPages "Section" "blog" }}

  {{ $paginator := .Paginate $pages }}

  {{ range $paginator.Pages }}
    {{ with .Content }}{{ end }}
    {{ $page_css := .Scratch.Get "css" }}
    {{ with $page_css }}
      {{ $css_list := $.Scratch.Get "css" }}
      {{ . | merge $css_list | $.Scratch.Set "css" }}
    {{ end }}
    {{ $page_js := .Scratch.Get "js" }}
    {{ with $page_js }}
      {{ $js_list := $.Scratch.Get "js" }}
      {{ . | merge $js_list | $.Scratch.Set "js" }}
    {{ end }}
  {{ end }}

  {{ $paginator | .Scratch.Set "paginator" }}

{{ end }}

{{ define "main" }}

  {{ $paginator := .Scratch.Get "paginator" }}

  {{ range $paginator.Pages }}
  <article class="h-entry">
    {{ partial "heading.html" . }}
    <p class="p-summary">{{ .Summary }}</p>
    {{ if .Truncated }}
      <p>
        <a class="u-clickable" href="{{ .RelPermalink }}">Read More…</a>
      </p>
    {{ end }}
  </article>
  {{ end }}

  {{ partial "pagination.html" . }}

{{ end }}

M layouts/partials/assets.html => layouts/partials/assets.html +25 -0
@@ 3,6 3,31 @@
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.webmanifest">

{{ $base_css := resources.Get "css/base.tpl.css" | resources.ExecuteAsTemplate "css/base.css" . }}

{{ $site_css := $base_css }}

{{ with site.Params.css }}
  {{ $css_list := slice $site_css }}
  {{ range . }}
    {{ $custom_css := resources.Get . }}
    {{ $css_list = $css_list | append $custom_css }}
  {{ end }}
  {{ $site_css = $css_list | resources.Concat "css/base.css" }}
{{ end }}

{{ minify $site_css | fingerprint | .Page.Scratch.SetInMap "css" "base" }}

{{ with site.Params.js }}
  {{ $js_list := slice }}
  {{ range . }}
    {{ $custom_js := resources.Get . }}
    {{ $js_list = $js_list | append $custom_js }}
  {{ end }}
  {{ $site_js := $js_list | resources.Concat "js/base.js" }}
  {{ minify $site_js | fingerprint | $.Page.Scratch.SetInMap "js" "base" }}
{{ end }}

{{ range .Scratch.GetSortedMapValues "css" }}
  <link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{ end }}

M layouts/partials/banner.html => layouts/partials/banner.html +6 -6
@@ 1,8 1,8 @@
<nav>
  <div class="Banner">
    <h1 class="Banner-title"><a class="Banner-link" href="{{ "" | absURL }}">{{ site.Title }}</a></h1>
    <ul class="Banner-menu">
      <li class="Banner-item Banner-search">
  <div class="banner">
    <h1 class="banner-title"><a class="banner-link" href="{{ "" | absURL }}">{{ site.Title }}</a></h1>
    <ul class="banner-menu">
      <li class="banner-item banner-search">
        <form class="Search-form" role="search" action="https://duckduckgo.com/" method="GET" accept-charset="UTF-8">
          <input type="hidden" name="sites" value="{{ .Site.BaseURL }}">
          <label>


@@ 18,8 18,8 @@
        </form>
      </li>
      {{- range site.Menus.nav -}}
      <li class="Banner-item">
        <a class="Banner-link" href="{{ .URL | absURL }}">{{ .Name }}</a>
      <li class="banner-item">
        <a class="banner-link" href="{{ .URL | absURL }}">{{ .Name }}</a>
      </li>
      {{- end -}}
    </ul>

M layouts/partials/footer.html => layouts/partials/footer.html +2 -4
@@ 1,5 1,3 @@
{{ with site.Params.footer }}
<footer class="Footer">
  <small>{{ . | safeHTML }}</small>
<footer class="footer">
  <small>Content on this site is licensed <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a></small>
</footer>
{{ end }}

M layouts/partials/heading.html => layouts/partials/heading.html +2 -10
@@ 1,10 1,2 @@
<header>
  <h2 class="Heading p-name"><a class="u-url u-uid" href="{{ .RelPermalink }}" rel="bookmark">{{ .Title }}</a></h2>
  <p class="Subheading">
    {{ with .PublishDate | default nil }}
    <time class="dt-published" datetime="{{ .Format "2006-01-02T15:04:05Z07:00" }}">
      {{ .Format "January 2, 2006" }}
    </time>
    {{ end }}
  </p>
</header>
<h1 class="heading p-name"><a class="u-url u-uid" href="{{ .RelPermalink }}" rel="bookmark">{{ .Title }}</a></h1>
{{ partial "subheading.html" . }}

M layouts/partials/link.html => layouts/partials/link.html +0 -4
@@ 3,7 3,3 @@
{{ range .AlternativeOutputFormats }}
  {{ printf "<link rel=%q type=%q href=%q title=%q>" .Rel .MediaType .RelPermalink site.Title | safeHTML }}
{{ end }}

{{ with resources.Get "js/count.js" }}
  <link rel="preconnect" href="https://stats.gpanders.com">
{{ end }}

D layouts/partials/pagination.html => layouts/partials/pagination.html +0 -12
@@ 1,12 0,0 @@
{{ $paginator := .Scratch.Get "paginator" }}

{{ if gt $paginator.TotalPages 1 }}
  <nav class="Pagination">
    {{ with $paginator.Prev }}
      <a href="{{ .URL }}" rel="prev">« Previous</a>
    {{ end }}
    {{ with $paginator.Next }}
      <a href="{{ .URL }}" rel="next">Next »</a>
    {{ end }}
  </nav>
{{ end }}

M layouts/partials/sidebar.html => layouts/partials/sidebar.html +21 -30
@@ 1,31 1,22 @@
<section class="Sidebar">
  <div class="h-card">
    <h2 class="p-name"><a class="u-url" href="{{ "" | absURL }}">Gregory Anders</a></h2>
    <div class="p-note">
      <p>Electrical and computer engineer and open source software enthusiast.</p>
      <p>I use this site to write about things I learn or find interesting.</p>
    </div>
    <h3>Email</h3>
    <p class="u-email"><a rel="me" href="mailto:contact@gpanders.com">contact@gpanders.com</a></p>
    </h4>
    <h3>PGP</h3>
    <p class="u-key"><a href="/publickey.txt">56E93C2FB6B08BDB</a></p>
    <h3>Questions or comments?</h3>
    <p>Send a message to my <a href="https://lists.sr.ht/~gpanders/public-inbox">public inbox</a>.</p>
    <h3>Other places to find me</h3>
    <ul>
      <li><a rel="me" href="https://git.sr.ht/~gpanders">sourcehut</a></li>
      <li><a rel="me" href="https://github.com/gpanders">GitHub</a></li>
      <li><a rel="me" href="https://www.goodreads.com/user/show/23021370-gregory">Goodreads</a></li>
      <li><a rel="me" href="https://news.ycombinator.com/user?id=gpanders">Hacker News</a></li>
<aside class="sidebar">
  <p class="h-card p-name"><a class="u-url" href="{{ "" | absURL }}">Gregory Anders</a></p>
  <form class="search-form" role="search" action="https://duckduckgo.com/" method="GET" accept-charset="UTF-8">
    <input type="hidden" name="sites" value="{{ .Site.BaseURL }}">
    <label class="search-input">
      <input name="q" aria-label="Search" placeholder="Search…" tabindex="0" autocomplete="off" autocapitalize="off" required>
    </label>
    <label class="search-icon">
      <input type="image" src="/search.svg" alt="Search" aria-label="Submit">
    </label>
    <ul class="search-results" style="display: none"></ul>
  </form>
  <nav>
  {{- range site.Menus.nav -}}
    <ul class="nav-menu">
      <li class="nav-item">
        <a class="nav-link" href="{{ .URL | absURL }}">{{ .Name }}</a>
      </li>
    </ul>
  </div>

  <h3>Featured Projects</h3>
  <dl class="Project-list">
    {{ range where (where .Site.RegularPages "Section" "projects") ".Params.featured" "eq" true }}
    <dt><a href="{{ with .Params.href }}{{ . }}{{ else }}{{ .RelPermalink }}{{ end }}">{{ .Title }}</a></dt>
    <dd>{{ .Summary }}</dd>
    {{ end }}
  </dl>
</section>
  {{- end -}}
  </nav>
</aside>

A layouts/partials/subheading.html => layouts/partials/subheading.html +7 -0
@@ 0,0 1,7 @@
<p class="subheading">
  {{ with .PublishDate | default nil }}
  <time class="dt-published" datetime="{{ .Format "2006-01-02T15:04:05Z07:00" }}">
    {{ .Format "January 2, 2006" }}
  </time>
  {{ end }}
</p>

M layouts/projects/list.html => layouts/projects/list.html +13 -8
@@ 1,14 1,19 @@
{{ define "main" }}

{{ partial "heading.html" . }}
{{ .Content }}
<ul class="List">
  {{ range .Pages }}
  <li class="List-item">
    <h2 class="List-link"><a href="{{ with .Params.href }}{{ . }}{{ else }}{{ .RelPermalink }}{{ end }}">{{ .Title }}</a></h2>
    <p>{{ .Summary }}</p>
  </li>

{{ range where .Pages ".Params.featured" "eq" true  }}
  <p class="heading p-name"><a href="{{ .Param "href" }}">{{ .Title }}</a></p>
  {{ if .Content }}
    <details>
      <summary class="subheading">{{ .Summary }}</summary>
      <p>{{ .Content }}</p>
    </details>
  {{ else }}
    {{ with .Summary }}
      <p class="subheading">{{ . }}</p>
    {{ end }}
  {{ end }}
</ul>
{{ end }}

{{ end }}

D layouts/shortcodes/projects.html => layouts/shortcodes/projects.html +0 -9
@@ 1,9 0,0 @@
<ul>
{{ range where (where .Site.RegularPages "Section" "projects") ".Params.featured" "eq" true }}
<li>
  <div class="Project-link"><a href="{{ with .Params.href }}{{ . }}{{ else }}{{ .RelPermalink }}{{ end }}">{{ .Title }}</a></div>
  <div class="Project-desc">{{ .Summary }}</div>
</li>
{{ end }}
</ul>


A static/search.svg => static/search.svg +3 -0
@@ 0,0 1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" aria-hidden="true" height="16" width="16" viewBox="0 0 515.558 515.558">
  <path fill="#ccc" d="m378.344 332.78c25.37-34.645 40.545-77.2 40.545-123.333 0-115.484-93.961-209.445-209.445-209.445s-209.444 93.961-209.444 209.445 93.961 209.445 209.445 209.445c46.133 0 88.692-15.177 123.337-40.547l137.212 137.212 45.564-45.564c0-.001-137.214-137.213-137.214-137.213zm-168.899 21.667c-79.958 0-145-65.042-145-145s65.042-145 145-145 145 65.042 145 145-65.043 145-145 145z"/>
</svg>

D themes/hugo-flex => themes/hugo-flex +0 -1
@@ 1,1 0,0 @@
Subproject commit e31c9f9308646f3f233735bda5e8a5a9c36fbd9c