Compare commits

...
Sign in to create a new pull request.

41 commits

Author SHA1 Message Date
e6d4e0cf0f Hugo's Dictionary API post
Squashed commit of the following:

commit b507cf8be2ca46ce4b88e3292ef173a0b5e3606f
Author: Eryn Wells <eryn@erynwells.me>
Date:   Sun Nov 6 00:23:05 2022 -0700

    Wrap up this blog post

commit 6ed0c777e7c33b0819f7d7a896fce60f75a13fe3
Author: Eryn Wells <eryn@erynwells.me>
Date:   Sat Oct 15 10:20:03 2022 -0700

    WIP Hugo Dictionary API post
2022-11-15 17:45:19 -08:00
c23711db55 Add a blank rss_item.rss template as a catch-all for pages that should not be in the feed 2022-11-15 17:45:19 -08:00
d7accc69ab Put - around $scheme declaration in atom_entry_metadata 2022-11-15 17:45:19 -08:00
ac9112318c Do not escape .Content in the RSS feed templates 2022-11-15 17:45:19 -08:00
ceee419602 Move index templates up to layouts/ 2022-11-15 17:45:19 -08:00
cb90d28de0 Break up the RSS template into item templates, like I did for atom 2022-11-15 17:45:19 -08:00
d7283d6bce Rename the atom_entry templates with .atom suffix 2022-11-15 17:45:19 -08:00
10ac4747dc OOPS! Add back <a> tags to the site menu 2022-11-15 17:45:19 -08:00
bc42979aa4 Remove the back button from photo posts 2022-11-15 17:45:19 -08:00
64d26e5f4f Clean up the site header template a little bit 2022-11-15 17:45:19 -08:00
80d2d27a3a Convert the social menu to a config driven version 2022-11-15 17:45:19 -08:00
106e811c16 Generate a feed.atom too 2022-11-15 17:45:19 -08:00
ad6439b15a Always include <content> in photos atom entry 2022-11-15 17:45:19 -08:00
6b09d12525 Add alt text to the Harpswell post 2022-11-15 17:45:19 -08:00
d3e36a67d4 Add an inline <img> in the photo Atom entry 2022-11-15 17:45:19 -08:00
a06a9f6fcb Use the photo_thumbnail partial in the li_thumbnail_in_grid template 2022-11-15 17:45:19 -08:00
b6f2d7f1a6 Clean up formatting of photo shortcode 2022-11-15 17:45:19 -08:00
7d3b87bfd2 Remove <author> from the Atom entry metadata 2022-11-15 17:45:18 -08:00
dc360fe079 OOPS! Fix permalinks on photo pages 2022-11-15 17:45:18 -08:00
762e657c98 Add a set of templates to generate an Atom feed! 2022-11-15 17:45:18 -08:00
6c5fa3c81a Update the photo_thumbnail template to return the thumbnail itself, unmodified, if no changes are required 2022-11-15 17:45:18 -08:00
2fad1714a1 Reformat the head template a little bit 2022-11-15 17:45:18 -08:00
571f704998 Get the Atom output type all set up
Atom feed is generated at feed.xml using the index.atom.xml template
2022-11-15 17:45:18 -08:00
cddf9d5294 Add email to Author config 2022-11-15 17:45:18 -08:00
8a16e94621 Convert site config to YAML and move it to config/
Keep the old site config.toml around just in case.
2022-11-15 17:45:18 -08:00
a42f0c6a61 Add photo thumbnail, category, series, and tags to RSS items 2022-11-15 17:45:18 -08:00
42a6b500d6 Add orrs-island photo and a bunch of metadata to some posts 2022-11-15 17:45:18 -08:00
811b33deba Clean up the development CSS styles a little bit 2022-11-15 17:45:18 -08:00
60905652e4 Remove the .post-content section around {{ .Content }} 2022-11-15 17:45:18 -08:00
1345a7ee02 Add the series to the content header 2022-11-15 17:45:18 -08:00
48b2a79e0a Move footer tags list to a partial so photos and blogs can use the same template
Simplify the blog post layout by removing the <article> tag
2022-11-15 17:45:18 -08:00
4481164884 Add Harpswell Sunset post 2022-11-15 17:45:18 -08:00
35a8f683de Add hugo-new-photo.py to create a photo post from a list of photos 2022-11-15 17:45:17 -08:00
00e2b5ff03 Use .HasShortcode instead of setting the "includes_" variables in .Page.Store 2022-11-15 17:45:16 -08:00
550d8f5bb0 Use .Page.Store instead of .Page.Scratch for conditional includes of support JS
I saw this on one of the Hugo documentation pages, so I copied it. I am not sure what the difference is.
2022-11-15 17:45:16 -08:00
1429f7e439 Try to fix the debug EXIF info table -- I don't think this quite does it 2022-11-15 17:45:16 -08:00
578a504cad Let the photos section adapt to light/dark mode 2022-11-15 17:45:16 -08:00
db1003017f Add a shortcode to embed a photo post in a blog post 2022-11-15 17:45:16 -08:00
2c02361e20 Redo the blog list layout to make it work a little better on narrow screens 2022-11-15 17:45:16 -08:00
278c220693 Draft 2 2022-10-30 11:29:36 -07:00
b0aec51db0 New England draft 2022-10-28 16:01:53 -04:00
53 changed files with 847 additions and 280 deletions

View file

@ -0,0 +1,2 @@
name: Eryn Wells
email: eryn@erynwells.me

View file

@ -0,0 +1,4 @@
baseURL: https://erynwells.me/
languageCode: en-US
title: Erynwells.me
defaultContentLanguage: en

View file

@ -0,0 +1,4 @@
en:
weight: 1
es:
weight: 2

View file

@ -0,0 +1,5 @@
highlight:
anchorLineNos: true
lineNos: true
lineNumbersInTable: false
noClasses: false

View file

@ -0,0 +1,6 @@
application/rss+xml:
delimiter: .
suffixes: [rss]
application/atom+xml:
delimiter: .
suffixes: [atom, xml]

39
config/_default/menu.yaml Normal file
View file

@ -0,0 +1,39 @@
main:
- identifier: blog
name: Blog
url: /blog/
weight: 10
- identifier: photos
name: Photos
url: /photos/
weight: 20
- identifier: about
name: About
url: /about/
weight: 30
social:
- identifier: twitter
name: Twitter
url: https://twitter.com/erynofwales
weight: 10
params:
shortName: tw
- identifier: github
name: Github
url: https://github.com/erynofwales
weight: 20
params:
shortName: gh
- identifier: instagram
name: Instagram
url: https://instagram.com/erynofwales
weight: 30
params:
shortName: ig
- identifier: feed
name: Feed
url: /feed.atom
weight: 40
params:
shortName: feed
targetBlank: false

View file

@ -0,0 +1,8 @@
RSS:
mediatype: application/rss+xml
baseName: feed
suffixes: [rss]
Atom:
mediatype: application/atom+xml
baseName: feed
suffixes: [atom, xml]

View file

@ -0,0 +1,2 @@
home: [HTML, Atom, RSS]
page: [HTML, JSON]

View file

@ -0,0 +1,4 @@
twitter: erynofwales
github: erynofwales
instagram: erynofwales
description: Home page of Eryn Rachel Wells

View file

@ -0,0 +1,2 @@
blog: blog/:year/:month/:slug/
photos: photos/:year/:month/:slug/

View file

@ -0,0 +1,2 @@
twitter:
enableDNT: true

View file

@ -0,0 +1,2 @@
twitter:
disableInlineCSS: true

View file

@ -0,0 +1,4 @@
category: categories
location: locations
series: series
tag: tags

View file

@ -0,0 +1,151 @@
---
title: "Hugo's Dictionary API"
date: 2022-10-13T10:19:02-07:00
categories: ["Tech"]
tags: ["Hugo", "Web", "API Design"]
series: "Erynwells.me Development"
---
Hugo's templating system has support for dictionaries. Unfortunately the API for
working with them is, frankly, awful. While working on developing some new
templates for this site, I had to figure out how to build up dictionary data
structures and it took me a _long_ time to figure out how to do some basic
operations with them.
Here's a quick summary of what I found.
## Creating Dictionaries
The function to create a dictionary is called [`dict`][dict] and it takes a
variable number of arguments that alternate between keys and values. It reminds
me of this [bizarre and backwards NSDictionary API][nsdictionary-init] in Apple's
Foundation framework. Keys must be strings (or string slices) and values can be
anything. So this:
{{< figures/code >}}
```go-html-template
{{ $d := dict "a" 1 "b" 2 "c" 3 }}
```
{{< /figures/code >}}
creates a structure that looks like this JSON object:
{{< figures/code >}}
```json
{ "a": 1, "b": 2, "c": 3 }
```
{{< /figures/code >}}
You can also create an empty dictionary by calling `dict` with no arguments.
{{< figures/code >}}
```go-html-template
{{ $d := dict }}
```
{{< /figures/code >}}
## Accessing Keys and Values
Statically, you can get a single item in a dictionary with dot syntax. Below,
`$item` will get the value 1.
{{< figures/code >}}
```go-html-template
{{ $item := (dict "a" 1 "b" 2 "c" 3).a }}
```
{{< /figures/code >}}
If you want to get a value with a key you get at render time, you can use the
[`index`][index] function. In the snippet below, `$item` will get the value of
`"b"`, which is 2.
{{< figures/code >}}
```go-html-template
{{ $key := "b" }}
{{ $item := index $key (dict "a" 1 "b" 2 "c" 3) }}
```
{{< /figures/code >}}
`index` doesn't make much sense to me as a verb for accessing values in a
dictionary. It sounds more like an array function, and indeed it's the function
that gives you access to items in arrays. I would like to see another function
with a more dictionary-sounding name, like `get` or `value` or `item`, even if
it were just an alias for `index` underneath.
## Adding Items to a Dictionary
This is a bit complex because, as far as I can tell, dictionaries are immutable.
So, if you want to update a dictionary, you need to combine two dictionaries and
then save it back to the original variable. The [`merge`][merge] function does
that. Here's a snippet:
{{< figures/code >}}
```go-html-template
{{ $d := dict "a" 1 "b" 2 "c" 3 }}
{{ $d = merge $d (dict "b" 4) }}
{{ $item = index "b" $d }}
```
{{< /figures/code >}}
`merge` takes a variable number of arguments, and merges dictionaries left to
right. So, items in dictionaries later in the argument list will override items
in dictionaries earlier in the list.
Just to underscore, you have to set the update dictionary back to the original
variable to complete the update, hence the `$d = ...`.
All that is to say: at the end of that snippet, `$item` will get the value 4.
## A Complex Example: A Dictionary of Arrays
For the previously mentioned template changes I was making, I was updating the
`terms` template for my category taxonomy. For each category, I wanted to show
one section per tag, and a list of all the posts with that tag underneath.
My categories are high level groups like "Tech," "Music," and "Travel." Tags are
more specific topics for the post like "Web" or "Compositions." Pages only ever
have one category but they can have multiple tags.
A `terms` template lets you access an array of terms, and the pages associated
with those terms. You can access the tags attached to a page with the
`.GetTerms` function. Here's what I did, and then I'll talk through it:
{{< figures/code >}}
```go-html-template
{{- $pagesByTag := dict -}}
{{- range $page := .Pages -}}
{{- range $tag := .GetTerms "tags" -}}
{{- $tagName := $tag.Name -}}
{{- if not (in $pagesByTag $tagName) -}}
{{- $pagesByTag = merge $pagesByTag
(dict $tagName (slice $page)) -}}
{{- else -}}
{{- $pagesForTag := index $pagesByTag $tagName -}}
{{- $pagesForTag = $pagesForTag | append $page -}}
{{- $pagesByTag = merge $pagesByTag
(dict $tagName $pagesForTag) -}}
{{- end -}}
{{- end -}}
{{- end -}}
```
{{< /figures/code >}}
`$pagesByTag` is my empty dictionary. It will hold tag names as keys, each
pointing to a slice (array) of page objects. For each page, I get its list of
tags. For each tag, I check `$pagesByTag` to see if it already has a key/value
pair for that tag. If not, I create a new entry in `$pagesByTag` with `merge`.
If it does already, I get the slice for that tag with `index`, add the Page to
the slice with `append`, and then merge the updated slice back into
`$pagesByTag` with `merge`.
It's not too bad once it's all spelled out, but it does feel like more work than
it should take for such simple operations.
I think this API could be improved substantially with some new functions that
operate specifically on dictionaries and that have clear names that describe
what they do.
[dict]: https://gohugo.io/functions/dict/
[index]: https://gohugo.io/functions/index-function/
[merge]: https://gohugo.io/functions/merge/
[nsdictionary-init]: https://developer.apple.com/documentation/foundation/nsdictionary/1574181-dictionarywithobjectsandkeys?language=objc

View file

@ -0,0 +1,64 @@
---
title: "New England"
date: 2022-10-28T16:01:10-04:00
draft: true
categories: ["Travel"]
locations:
- Scituate, MA
- Boston, MA
- Massachusettes
- Portland, ME
- Maine
- United States
tags:
- Friends
- Family
---
For the second year in a row, a group of high school friends of mine have
planned a trip together for a week in October. Last year, I wrote about [our
trip to the Pacific Northwest][pnw]. This year, we decided on a trip to New
England, splitting our time between Boston and an AirBnb an hour up the Maine
coast from Portland. Our group is a bit different this year -- a couple people
couldn't make it, another joined for the first time, and happily {{< tess >}}
was able to come along too.
## Scituate
Tess and I left a few days before the trip started so we could travel down to
Scituate, her hometown, to visit her family and show me around her childhood
haunts. It's a charming coast New England town, full of history and [deep
connections to Ireland][ssiht] on account of its many Irish and Irish-descended
residents.
{{< photo "2022/10/scituate-light" >}}
## Boston
The first part of the friends' trip was a few days in Boston. We stated in
Somerville and explored downtown Boston via the MBTA. We spent a full day
exploring the city on foot. Tess played tour guide for the other nine of us -- a
part (I think) she relishes and (I believe) does exceptionally well. We also
checked out the Isabella Stewart Garnder museum, a bizarre and fascinating
house-turned-museum, and the site of the highest-value unsolved heist in the
world.
{{< photo "2022/10/gardner-museum" >}}
Our second day in Boston, we took the ferry to Salem, MA. Salem is totally
overrun with tourists during October each year because of its history as the
site of the famous [Salem Witch Trials][salem-witch-trials]. We took the ferry
from Boston, visited the museum there and wandered around town for an afternoon.
It's a cute little town that really capitalizes on that witchy history. I
imagine the fulltime residents have a variety of feelings about how intense the
tourism gets this time of year.
In Boston, we rented two cars and drove the ten of us north, through Portsmouth,
New Hampshire, and Freeport, Maine -- stopping at the L.L. Bean flagship store on
the way -- to a rental house on Casco Bay.
## Maine
[pnw]: {{< ref "blog/2021/10/pnw-reunion-trip" >}}
[ssiht]: https://ssirishtrail.org
[salem-witch-trials]: https://en.wikipedia.org/wiki/Salem_witch_trials

View file

@ -1,24 +1,13 @@
:root {
--post-item-highlight-color: #efefef;
--tag-foreground-color: rgb(var(--super-dk-gray));
--tag-background-color: rgb(var(--super-lt-gray));
--tag-spacer-foreground-color: rgb(var(--super-dk-gray));
--tag-hover-background-color: rgb(var(--sub-lt-gray));
}
@media (prefers-color-scheme: dark) {
:root {
--post-item-highlight-color: #121212;
--tag-foreground-color: rgb(var(--sub-lt-gray));
--tag-background-color: rgb(var(--dk-gray));
--tag-spacer-foreground-color: rgb(var(--super-dk-gray));
--tag-hover-background-color: rgb(var(--super-dk-gray));
--tag-hover-foreground-color: rgb(var(--mid-gray));
}
}
.post-content > .highlight { margin-block-end: var(--body-item-spacing); }
.blog > .highlight { margin-block-end: var(--body-item-spacing); }
.post-nav {
align-items: baseline;
@ -34,54 +23,60 @@
margin-block-start: var(--body-item-spacing);
}
.blog .tags {
display: flex;
padding-inline-start: 0;
.blog.list > ul {
list-style: none;
}
.blog .tags li {
background-color: var(--tag-background-color);
color: var(--tag-foreground-color);
border-radius: 4px;
display: inline-block;
font-size: 75%;
letter-spacing: 1px;
.blog.list > ul > li {
align-items: baseline;
border-radius: 6px;
display: grid;
gap: 1rem;
grid-template-columns: minmax(min-content, 10vh) minmax(min-content, 3vh) auto max-content;
margin-block-end: 0.25rem;
transition: background-color 0.25s;
}
.blog .tags li:hover {
background-color: var(--tag-hover-background-color);
.blog.list > ul > li:hover {
background-color: var(--post-item-highlight-color);
}
.blog .tags li a {
.blog.list > ul > li > a {
color: inherit;
display: block;
height: 100%;
width: 100%;
padding: 0.6rem 1rem;
}
.blog .tags li a:hover {
color: var(--tag-hover-foreground-color);
.blog.list > ul > li > a:hover {
text-decoration: none;
}
.blog .tags li + li { margin-inline-start: 1rem; }
.blog .tags li.chevron + li { margin-inline-start: 0 }
.blog .tags .chevron {
align-items: center;
border: 0;
border-radius: 0;
color: var(--tag-spacer-foreground-color);
background-color: inherit;
display: flex;
justify-content: center;
margin-inline-start: 0;
padding-inline-start: 1px;
width: 2rem;
.blog.list > ul > li > .draft {
align-self: center;
}
.blog .tags .chevron:hover {
color: var(--tag-background-color);
background-color: inherit;
@supports (grid-template-columns: subgrid) {
.blog.list {
display: grid;
gap: 1rem;
grid-template-columns: minmax(min-content, 10vh) minmax(min-content, 3vh) auto max-content;
}
.blog.list > ul {
display: grid;
row-gap: 0.25rem;
grid-column: 1 / -1;
grid-template-columns: subgrid;
list-style: none;
}
.blog.list > ul > li {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
margin-block-end: 0;
}
.blog.list > h5 {
grid-column: 1 / -1;
margin-block: 1rem 0;
}
.blog.list > h5:first-child {
margin-block-start: 0;
}
}
.blog.list > ul > li > :first-child {
text-align: end;
}

View file

@ -4,6 +4,13 @@ slug: sappho-the-eresian
date: 2022-08-04T15:32:20+02:00
draft: false
series: Greece
locations:
- Skala Eressos, Lesbos, Greece
- Lesbos
- Greece
- Σκαλα Ερεσού
- Λεσβος
- Ελλάδα
---
I fell in love with this piece of street art depicting Sappho as a modern woman

View file

@ -2,7 +2,13 @@
title: "Gardner Museum"
date: 2022-10-24T16:07:00-04:00
draft: false
series: ""
series: "Spruce Goose‼"
tags: ["Museums", "Gardens"]
locations:
- Boston, MA
- Massachusettes
- New England
- United States
---
Isabella Stewart Gardner was an obsecenely wealthy lady with a very strange and cool house.

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:365b6fdbfb2ff929e008bdc4b70c58820ecd00f255ebeb5956b4edc3f42fe4b0
size 3475571

View file

@ -0,0 +1,20 @@
---
title: Harpswell Sunset
date: 2022-10-28T14:19:58-07:00
draft: false
series: "Spruce Goose‼"
tags: ["Sunsets", "Ocean", "Friends"]
locations:
- Harpswell, ME
- Maine
- New England
- United States
resources:
- name: sunset
alt: "The sun sets over an inlet on Casco Bay. In the foreground is a fence, with a tidal mudflat beyond. There are several people out on the mudflat. There's another strip of land in the far distance, and a few boats moored to bouys in the water."
src: IMG_0380.jpeg
---
Maine did not disappoint on our last full day in Harpswell. The sunset was
gorgeous, and a bunch of us walk out on the mudflats to check out the literal
thousands of snails, barnicles, and seaweed.

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6f1202980dc20a208999fb83138ff6470940f71a4c62ca056ad15705b007c582
size 3641161

View file

@ -0,0 +1,19 @@
---
title: "Orrs Island"
date: 2022-10-28T11:21:06-07:00
draft: false
series: "Spruce Goose‼"
tags: ["Hiking", "Ocean"]
locations:
- Harpswell, ME
- Maine
- New England
- United States
---
We took a short hike on Orrs Island, near where we were staying. It was a small
loop trail in the ominously named "Devil's Back" trail area that wasn't
particularly strenous apart from the soft ground and many rocks and roots we had
to hike over.
We did have to do the limbo under a fallen tree though.

View file

@ -1,25 +1,20 @@
:root {
--body-code-background-color: rgb(var(--dk-gray));
--box-shadow-color: rgba(var(--dk-gray), 0.8);
--date-item-background-color: rgb(var(--lt-gray));
--heading-color: rgb(var(--white));
--html-color: rgb(var(--white));
--html-background-color: rgb(var(--black));
--photo-params-background-color: rgb(var(--lt-gray));
--photo-params-container-background-color: rgb(var(--super-lt-gray));
--photo-params-color: rgb(var(--sub-dk-gray));
--photo-params-border-color: rgb(var(--super-lt-gray));
}
@media (prefers-color-scheme: dark) {
:root {
--date-item-background-color: rgb(var(--dk-gray));
--photo-params-background-color: rgb(var(--dk-gray));
--photo-params-container-background-color: rgb(var(--sub-dk-gray));
--photo-params-color: rgb(var(--super-lt-gray));
--photo-params-border-color: rgb(var(--sub-dk-gray));
--platter-background-color: rgba(var(--black), var(--platter-background-opacity));
--separator-color: rgb(var(--dk-gray));
--twitter-icon: url(/icons/twitter-dark.svg);
--github-icon: url(/icons/github-dark.svg);
--instagram-icon: url(/icons/instagram-dark.svg);
--rss-icon: url(/icons/rss-dark.svg);
}
}
.photos.list {
@ -50,7 +45,7 @@
}
.photos.list > div {
background-color: #333;
background-color: var(--date-item-background-color);
border-radius: 3px;
width: 100%;
height: 100%;

76
hugo-new-photo.py Executable file
View file

@ -0,0 +1,76 @@
#!env/bin/python3
# Eryn Wells <eryn@erynwells.me>
'''
New script.
'''
import argparse
import datetime
import os.path
import shutil
import subprocess
from PIL import Image
from PIL.ExifTags import TAGS
PHOTOS_CONTENT_DIR = 'content/photos'
def parse_args(argv, *a, **kw):
parser = argparse.ArgumentParser(*a, **kw)
parser.add_argument('-n', '--dry-run', action='store_true')
parser.add_argument('-t', '--title', type=str)
parser.add_argument('photos', nargs='+')
args = parser.parse_args(argv)
return args
def main(argv):
args = parse_args(argv[1:], prog=argv[0])
earliest_exif_date = None
for photo in args.photos:
try:
image = Image.open(photo)
except IOError:
pass
raw_exif = image._getexif()
friendly_exif = {TAGS[k]: v for k, v in raw_exif.items() if k in TAGS}
date_string = f'{friendly_exif["DateTime"]} {friendly_exif["OffsetTime"]}'
exif_date = datetime.datetime.strptime(date_string, '%Y:%m:%d %H:%M:%S %z')
print(f'{photo} -> {exif_date.isoformat()}')
if not earliest_exif_date or exif_date < earliest_exif_date:
earliest_exif_date = exif_date
year = earliest_exif_date.year
month = earliest_exif_date.month
name = args.title if args.title else os.path.splitext(os.path.basename(photo))[0]
post_path = os.path.join(PHOTOS_CONTENT_DIR, str(year), str(month), name)
try:
hugo_command = ['hugo', 'new', '--clock', earliest_exif_date.isoformat(), post_path]
if not args.dry_run:
result = subprocess.run(hugo_command)
result.check_returncode()
else:
print(' '.join(hugo_command))
except subprocess.CalledProcessError:
print(f'Failed to create new Hugo post', file=sys.stderr)
return -1
for photo in args.photos:
print(f'Copy {photo} -> {post_path}')
try:
if not args.dry_run:
shutil.copy(photo, post_path)
except IOError:
print(f'Failed to copy {photo}', file=sys.stderr)
return -2
if __name__ == '__main__':
import sys
result = main(sys.argv)
sys.exit(0 if not result else result)

View file

@ -1,41 +0,0 @@
{{- $pctx := . -}}
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pctx.RegularPages -}}
{{- else -}}
{{- $pages = $pctx.Pages -}}
{{- end -}}
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>
<link>{{ .Permalink }}</link>
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
<generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
<language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
<managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
<webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
<copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
{{- with .OutputFormats.Get "RSS" -}}
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
{{- end -}}
{{ range $pages }}
{{ if ne .Params.rss_ignore true }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
<guid>{{ .Permalink }}</guid>
<description>{{ .Content | html }}</description>
</item>
{{ end }}
{{ end }}
</channel>
</rss>

View file

@ -0,0 +1,4 @@
{{/*
Intentionally empty to stop pages that shouldn't be included in the RSS feed
from being rendered with the default RSS template.
*/}}

View file

@ -7,19 +7,19 @@
{{ end }}
{{ define "styles" }}
{{- if .Page.Scratch.Get "includes_railroad_diagram" -}}
{{- if .HasShortcode "figures/railroad" -}}
<link rel="preload stylesheet" as="style" href="{{ `styles/railroad.css` | absURL }}">
{{- end -}}
<link rel="preload stylesheet" as="style" href="{{ `styles/monokai.css` | absURL }}">
{{ end }}
{{ define "scripts" }}
{{- if .Page.Scratch.Get "includes_railroad_diagram" -}}
{{- if .HasShortcode "figures/railroad" -}}
<script defer type="module" src="{{ `scripts/railroad.js` | absURL }}"></script>
<script defer type="module" src="{{ `scripts/railroad-utils.js` | absURL }}"></script>
{{- end -}}
{{- if .Page.Scratch.Get "includes_p5_sketch" -}}
{{- if .HasShortcode "figures/p5" -}}
<script defer src="{{ `scripts/p5-1.4.1.min.js` | absURL }}"></script>
<script defer src="{{ `scripts/sketch-utils.js` | absURL }}"></script>
{{- end -}}

View file

@ -0,0 +1,6 @@
<entry>
{{ partial "atom_entry_metadata.xml" . }}
{{- if .Content -}}
{{ `<content type="html"><![CDATA[` | safeHTML }}{{ .Content }}]]></content>
{{- end -}}
</entry>

View file

@ -1,8 +1,6 @@
<li>
<time class="nobreak" datetime="{{ .Date | time.Format "2006-01-02" }}">{{ .Date | time.Format "January" }}</time>
<time class="nobreak" datetime="{{ .Date | time.Format "2006-01-02" }}">{{ .Date | time.Format "2" }}</time>
<div class="title">
<a href="{{ .Permalink }}">{{ .Title }}</a>
{{ partial "development/draft_tag.html" . }}
</div>
</li>

View file

@ -3,18 +3,16 @@
{{ end }}
{{ define "main" }}
<section id="by-date">
{{- range .Pages.ByDate.GroupByDate "2006" -}}
<h6>{{ .Key | title }}</h6>
<ul class="post-list">
{{- range .Pages.ByDate.GroupByDate "2006" -}}
<h5>{{ .Key | title }}</h5>
<ul>
{{- range .Pages -}}
{{- if or (not .Draft) (not hugo.IsProduction) -}}
{{- .Render "li_grid_with_date" -}}
{{- end -}}
{{- end -}}
</ul>
{{- end -}}
</section>
</ul>
{{- end -}}
{{ end }}
{{ define "footer" }}

View file

@ -0,0 +1,6 @@
<item>
{{ partial "rss_item_metadata.rss" . }}
<description>{{ `<![CDATA[` | safeHTML }}
{{ .Content }}
]]></description>
</item>

28
layouts/index.atom.atom Normal file
View file

@ -0,0 +1,28 @@
{{- $pctx := . -}}
{{- if .IsHome -}} {{ $pctx = .Site }} {{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pctx.RegularPages -}}
{{- else -}}
{{- $pages = $pctx.Pages -}}
{{- end -}}
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}} {{- $pages = $pages | first $limit -}} {{- end -}}
{{ printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ .Site.Title }}</title>
<link href="{{ `/feed.xml` | absURL }}" rel="self" />
<link href="{{ .Permalink }}" />
{{ if not .Date.IsZero }}<updated>{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</updated>{{ end }}
<id>{{ .Permalink }}</id>
{{ with .Site.Author.name }}
<author>
<name>{{ . }}</name>
{{ with $.Site.Author.email }}<email>{{ . }}</email>{{ end }}
<uri>{{ $.Site.Home.Permalink }}</uri>
</author>
{{ end }}
<generator version="{{ hugo.Version }}" uri="https://gohugo.io">Hugo {{ hugo.Version }}</generator>
<rights>© {{ now.Year }} Eryn Wells</rights>
{{ range $pages }}{{ .Render "atom_entry" }}{{ end }}
</feed>

35
layouts/index.rss.rss Normal file
View file

@ -0,0 +1,35 @@
{{- $pageContext := . -}}
{{- if .IsHome -}}
{{ $pageContext = .Site }}
{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pageContext.RegularPages -}}
{{- else -}}
{{- $pages = $pageContext.Pages -}}
{{- end -}}
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ .Site.Title }}</title>
<link>{{ .Permalink }}</link>
<description>Recent content on {{ .Site.Title }}</description>
<generator>Hugo {{ hugo.Version }} -- gohugo.io</generator>
{{ with .Site.LanguageCode }}<language>{{ . }}</language>{{ end }}
{{ with .Site.Author }}
<managingEditor>{{ .name }} &lt;{{ .email }}&gt;</managingEditor>
<webMaster>{{ .name }} &lt;{{ .email }}&gt;</webMaster>
{{ end }}
{{ with .Site.Copyright }}<copyright>{{ . }}</copyright>{{ end }}
{{ if not .Date.IsZero }}<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
{{ with .OutputFormats.Get "RSS" }}{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}{{ end }}
{{ range $pages }}{{ .Render "rss_item" }}{{ end }}
</channel>
</rss>

View file

@ -0,0 +1,10 @@
<title>{{ .Title }}</title>
<id>{{ .Permalink }}</id>
<published>{{ .Date.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</published>
<updated>{{ .Lastmod.Format "2006-01-02T15:04:05-07:00" | safeHTML }}</updated>
{{- range slice "series" "categories" "tags" -}}
{{- range $.GetTerms . -}}
{{- $scheme := (.Site.GetPage (printf "/%s" .Section)).Permalink -}}
<category term="{{ .Name }}" scheme="{{ $scheme }}" label="{{ .Title }}" />
{{- end -}}
{{- end -}}

View file

@ -0,0 +1,18 @@
<header>
{{ partial "development/draft_tag.html" . }}
<div class="post-title">
<h1>{{ .Title }}</h1>
{{ if not (eq .Type "page") }}
<div class="post-date"><time>{{ .Date | time.Format "January 2, 2006" }}</time></div>
{{ end }}
</div>
{{- if .Params.series -}}
{{- $series := .GetTerms "series" -}}
{{- if gt (len $series) 1 -}}
{{- errorf "More than one series for %s" .Permalink -}}
{{- end -}}
{{- with index $series 0 -}}
<span class="series"><a href="{{ .Permalink }}">{{ .Title }}</a></span>
{{- end -}}
{{- end -}}
</header>

View file

@ -1,3 +1,3 @@
{{ if in (.Site.BaseURL | string) "localhost" }}
{{ if .Draft }}<span class="draft">draft</span>{{ end }}
{{ if .Draft }}<span class="draft">d</span>{{ end }}
{{ end }}

View file

@ -0,0 +1,24 @@
{{- if or .Params.categories .Params.tags -}}
<ul class="tags">
{{- if .Params.categories -}}
{{- $categories := .GetTerms "categories" -}}
{{- if gt (len $categories) 1 -}}
{{- errorf "More than one category for %q" .Path -}}
{{- end -}}
{{- with index (.GetTerms "categories") 0 -}}
<li class="category"><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
{{- end -}}
{{- end -}}
{{- if and .Params.categories .Params.tags -}}
<li class="chevron noselect"></li>
{{- end -}}
{{- if .Params.tags -}}
{{- range .GetTerms "tags" -}}
<li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
{{- end -}}
{{- end -}}
</ul>
{{- end -}}

View file

@ -1,28 +1,23 @@
{{- $currentPage := . -}}
{{- $url := .RelPermalink -}}
<header class="site">
<div class="platter grid">
<h1 class="site">
<a class="site-name" href="{{ `` | absURL }}">Eryn Wells</a>
</h1>
{{ $url := .RelPermalink }}
{{ with site.Menus.main }}
<nav class="site bulleted">
{{ with site.Menus.main }}
{{- range . -}}
{{- if eq .URL $url -}}
<li class="active"><span>{{ .Name }}</span></li>
{{- else -}}
<li><a href="{{ .URL }}"><span>{{ .Name }}</span></a></li>
<li><a {{ if $currentPage.HasMenuCurrent "main" . }} class="active"{{ end }} href="{{ .URL }}"><span>{{ .Name }}</span></a></li>
{{- end -}}
{{- end -}}
</nav>
{{ end }}
</nav>
<nav class="social">
<li><a style="--url: var(--twitter-icon)" href="https://twitter.com/erynofwales" target="_blank" aria-label="twitter"><span>tw</span></a></li>
<li><a style="--url: var(--github-icon)" href="https://github.com/erynofwales" target="_blank" aria-label="github"><span>gh</span></a></li>
<li><a style="--url: var(--instagram-icon)" href="https://instagram.com/erynofwales" target="_blank" aria-label="instagram"><span>ig</span></a></li>
{{ with .OutputFormats.Get "rss" }}
<li><a style="--url: var(--rss-icon)" href="{{ .RelPermalink }}" aria-label="rss"><span>rss</span></a></li>
{{ with site.Menus.social }}
{{- range . -}}
{{- $targetBlank := .Params.targetBlank | default true -}}
<li><a style="--url: var(--{{ .Identifier }}-icon)" href="{{ .URL }}" {{ if $targetBlank }}target="_blank"{{ end }} aria-label="{{ .Name }}"><span>{{ .Params.shortName | default .Name }}</span></a></li>
{{- end -}}
{{ end }}
</nav>
</div>

View file

@ -0,0 +1,23 @@
{{- $thumbnailResource := .Resources.GetMatch (index .Page.Params "thumbnail")
| default (index (.Page.Resources.ByType "image") 0) -}}
{{- if not $thumbnailResource -}}
{{- errorf "No thumbnail available for %s" .Page.Permalink }}
{{- end -}}
{{ $orientation := partial "images/orientation_angle.html" $thumbnailResource }}
{{ $targetWidth := 0 }}
{{ if isset . "Width" }}{{ $targetWidth = .Width }}{{ else }}{{ $targetWidth = $thumbnailResource.Width }}{{ end }}
{{ $targetHeight := 0 }}
{{ if isset . "Height" }}{{ $targetHeight = .Height }}{{ else }}{{ $targetHeight = $thumbnailResource.Height }}{{ end }}
{{ $thumbnail := false }}
{{ if not (and (eq $orientation 0)
(eq $targetWidth $thumbnailResource.Width)
(eq $targetHeight $thumbnailResource.Height)) }}
{{ $thumbnail = $thumbnailResource.Fit (printf "%dx%d r%d" $targetWidth $targetHeight (sub 360 $orientation)) }}
{{ else }}
{{ $thumbnail = $thumbnailResource }}
{{ end }}
{{ return $thumbnail }}

View file

@ -0,0 +1,11 @@
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{ with .Site.Author.email }}<author>{{ . }}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
<guid>{{ .Permalink }}</guid>
{{- range slice "series" "categories" "tags" -}}
{{ range $.GetTerms . }}
{{- $domain := (.Site.GetPage (printf "/%s" .Section)).Permalink -}}
<category domain="{{ $domain }}">{{ .Title }}</category>
{{ end }}
{{- end -}}

View file

@ -1,43 +1,12 @@
<article class="post-single">
<header>
{{ partial "development/draft_tag.html" . }}
<div class="post-title">
<h1>{{ .Title }}</h1>
{{ if not (eq .Type "page") }}
<div class="post-date"><time>{{ .Date | time.Format "January 2, 2006" }}</time></div>
{{ end }}
</div>
</header>
{{ partial "content_header.html" . }}
<section class="post-content">
{{ .Content }}
</section>
{{ .Content }}
<footer>
{{- if or .Params.categories .Params.tags -}}
<ul class="tags">
{{- if .Params.categories -}}
{{- $categories := .GetTerms "categories" -}}
{{- if gt (len $categories) 1 -}}
{{- errorf "More than one category for %q" .Path -}}
{{- end -}}
{{- with index (.GetTerms "categories") 0 -}}
<li class="category"><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
{{- end -}}
{{- end -}}
{{- if and .Params.categories .Params.tags -}}
<li class="chevron noselect"></li>
{{- end -}}
{{- if .Params.tags -}}
{{- range .GetTerms "tags" -}}
<li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
{{- end -}}
{{- end -}}
</ul>
{{- end -}}
<footer>
{{ partial "footer_tags.html" . }}
{{ $pages := where site.RegularPages "Type" "in" site.Params.mainSections }}
{{ if and (gt (len $pages) 1) (in $pages . ) }}
{{- if and (gt (len $pages) 1) (in $pages . ) -}}
<nav class="post-nav">
{{ with $pages.Prev . }}
<a class="prev" href="{{ .Permalink }}"><span></span><span>{{ .Name }}</span></a>
@ -46,6 +15,5 @@
<a class="next" href="{{ .Permalink }}"><span>{{ .Name }}</span><span></span></a>
{{ end }}
</nav>
{{ end }}
</footer>
</article>
{{- end -}}
</footer>

View file

@ -0,0 +1,12 @@
{{- $thumbnail := partial "images/photo_thumbnail.html" . -}}
<entry>
{{ partial "atom_entry_metadata.xml" . }}
<link rel="enclosure" href="{{ $thumbnail.Permalink }}" type="{{ $thumbnail.MediaType }}" length="{{ len $thumbnail.Content }}" />
{{- $inlineThumbnail := partial "images/photo_thumbnail.html" (dict "Page" . "Width" 1280 "Height" 1280) -}}
<content type="html">{{ `<![CDATA[` | safeHTML }}
{{- with $inlineThumbnail -}}
<img src="{{ .Permalink }}">
{{- end -}}
{{- .Content -}}
]]></content>
</entry>

View file

@ -1,9 +1,6 @@
{{- $thumbnailResource := .Resources.GetMatch (index .Params "thumbnail")
| default (index (.Resources.ByType "image") 0) -}}
{{- $orientation := partial "images/orientation_angle.html" $thumbnailResource -}}
{{- $thumbnail := $thumbnailResource.Fit (printf "%dx%d r%d" 600 600 (sub 360 $orientation)) -}}
{{- $thumbnail := partial "images/photo_thumbnail.html" (dict "Page" . "Width" 600 "Height" 600) -}}
{{- $thumbnail = $thumbnail.Crop "600x600" -}}
{{- $altText := $thumbnailResource.Params.alt -}}
{{- $altText := $thumbnail.Params.alt -}}
<a href="{{ .RelPermalink }}" title="{{ .Title }}">
<img src="{{ $thumbnail.RelPermalink }}" {{ with $altText }}alt="{{ . }}"{{ end }}>
</a>

View file

@ -0,0 +1,8 @@
{{- $thumbnail := partial "images/photo_thumbnail.html" (dict "Page" . "Width" 1280 "Height" 1280) -}}
<item>
{{ partial "rss_item_metadata.rss" . }}
<description>{{ `<![CDATA[` | safeHTML }}
<img src="{{ $thumbnail.Permalink }}">
{{ .Content }}
]]></description>
</item>

View file

@ -3,17 +3,9 @@
{{ end }}
{{ define "main" }}
<nav><a class="back" href="{{ ref . `photos` }}">Back</a></nav>
{{ if .Title }}
<header>
{{ partial "development/draft_tag.html" . }}
<div class="post-title">
<h1 {{ with .Params.langs.title }}lang="{{ . }}"{{ end }}>{{ .Title }}</h1>
<div class="post-date"><time>{{ .Date | time.Format "January 2, 2006" }}</time></div>
</div>
</header>
{{ end }}
{{- if .Title -}}
{{ partial "content_header.html" . }}
{{- end -}}
{{ $photos := .Resources.ByType "image" }}
{{ if eq (len $photos) 0 }}
@ -40,6 +32,10 @@
</ul>
</figure>
{{ end }}
<footer>
{{ partial "footer_tags.html" . }}
</footer>
{{ end }}
{{ define "footer" }}

View file

@ -1,5 +1,4 @@
{{ $id := .Get "id" }}
{{ .Page.Scratch.Set "includes_p5_sketch" true }}
{{- $id := .Get "id" -}}
<div class="centered">
<figure class="p5-sketch {{ with .Get "bordered" }}bordered{{ end }}" id="{{ $id }}"></figure>
</div>

View file

@ -1,4 +1,3 @@
{{- $id := .Get "id" -}}
{{- .Page.Scratch.Set "includes_railroad_diagram" true -}}
<figure class="railroad-diagram" {{ if $id }}id="{{ $id }}"{{ end }}></figure>
{{ .Inner }}

View file

@ -0,0 +1,9 @@
{{- with $photoPage := $.Page.GetPage (printf "photos/%s" (.Get 0)) -}}
{{- $thumbnail := partial "images/photo_thumbnail.html" (dict "Page" . "Width" 1280 "Height" 1280) -}}
{{- $altText := $thumbnail.Params.alt | default .Title -}}
<a href="{{ .RelPermalink }}" title="{{ .Title }}">
<img src="{{ $thumbnail.RelPermalink }}"{{ with $altText }} alt="{{ . }}"{{ end }}>
</a>
{{- else -}}
{{- errorf "No page matching '%s'" (.Get 0) -}}
{{- end -}}

View file

@ -3,6 +3,10 @@
* Eryn Wells <eryn@erynwells.me>
*/
details:has(.photo-params.debug) {
margin-block-end: var(--body-item-spacing);
}
.draft {
color: red;
display: inline-block;
@ -34,25 +38,30 @@
width: max-content;
}
#debug-page-info details {
#debug-page-info > details {
margin: 0.5rem;
}
#debug-page-info summary {
#debug-page-info > summary {
font-family: var(--font-family-heading);
}
#debug-page-info table {
#debug-page-info > details > table {
border-collapse: collapse;
display: block;
margin-block-start: 0.5em;
margin-inline-start: 1em;
}
#debug-page-info td {
#debug-page-info > details > table > tbody > tr > td {
border: 1px solid rgb(var(--dk-gray));
padding: 0.3em;
}
#debug-page-info tr:nth-child(even) {
#debug-page-info > details > table > tbody > tr:nth-child(even) {
background-color: var(--separator-color);
}
.photo-params.debug {
width: 100%;
}

View file

@ -40,6 +40,7 @@
--body-code-background-color: rgb(var(--super-lt-gray));
--heading-color: rgb(var(--black));
--header-series-arrow-foreground-color: rgb(var(--sub-dk-gray));
--html-background-color: rgb(var(--white));
--html-color: rgba(var(--black), 0.8);
@ -50,6 +51,11 @@
--content-width: 80rem;
--tag-foreground-color: rgb(var(--super-dk-gray));
--tag-background-color: rgb(var(--super-lt-gray));
--tag-spacer-foreground-color: rgb(var(--super-dk-gray));
--tag-hover-background-color: rgb(var(--sub-lt-gray));
--transition-duration: 0.7s;
--social-menu-padding: 1rem;
@ -57,7 +63,7 @@
--twitter-icon: url(/icons/twitter.svg);
--github-icon: url(/icons/github.svg);
--instagram-icon: url(/icons/instagram.svg);
--rss-icon: url(/icons/rss.svg);
--feed-icon: url(/icons/rss.svg);
}
@media (prefers-color-scheme: dark) {
:root {
@ -66,6 +72,7 @@
--body-code-background-color: rgb(var(--dk-gray));
--heading-color: rgb(var(--white));
--header-series-arrow-foreground-color: rgb(var(--super-dk-gray));
--html-background-color: rgb(var(--black));
--html-color: rgba(var(--white), 0.8);
@ -73,10 +80,16 @@
--platter-background-color: rgba(var(--black), var(--platter-background-opacity));
--platter-backdrop-filter: brightness(0.66) blur(10px);
--tag-foreground-color: rgb(var(--sub-lt-gray));
--tag-background-color: rgb(var(--dk-gray));
--tag-spacer-foreground-color: rgb(var(--super-dk-gray));
--tag-hover-background-color: rgb(var(--super-dk-gray));
--tag-hover-foreground-color: rgb(var(--mid-gray));
--twitter-icon: url(/icons/twitter-dark.svg);
--github-icon: url(/icons/github-dark.svg);
--instagram-icon: url(/icons/instagram-dark.svg);
--rss-icon: url(/icons/rss-dark.svg);
--feed-icon: url(/icons/rss-dark.svg);
}
}
@ -334,6 +347,10 @@ main {
width: 100%;
}
main > header {
margin-bottom: var(--body-item-spacing);
}
main > :first-child { margin-block-start: 0; }
main > :last-child { margin-block-end: 0; }
@ -383,6 +400,18 @@ ol ol {
margin-inline-start: var(--body-item-spacing);
}
header > span.series {
font-size: 1.75rem;
letter-spacing: 1px;
margin-inline-start: 0.5em;
}
header > span.series::before {
color: var(--header-series-arrow-foreground-color);
content: "↳";
margin-inline-end: 0.25em;
}
.post-list {
list-style: none;
margin: 0;
@ -405,62 +434,13 @@ ol ol {
display: grid;
gap: 1em;
padding: 0.1em;
transition: background-color 0.25s;
}
@supports not (display: subgrid) {
.post-list li {
grid-template-columns: 100px 20px 3px auto;
grid-template-areas: "month day thing title";
}
}
@supports (display: subgrid) {
.post-list li {
display: subgrid;
}
}
.post-list li time:nth-of-type(1) {
grid-area: month;
text-align: end;
}
.post-list li time:nth-of-type(2) {
grid-area: day;
text-align: end;
}
.post-list li .title {
font-family: var(--font-family-body);
grid-area: title;
text-align: start;
}
.post-list li:hover {
background-color: var(--post-item-highlight-color);
}
.post-list h1 {
font-size: inherit;
font-weight: normal;
margin: 0;
padding: 0;
}
.post-list a {
color: inherit;
}
.post-list a:hover {
text-decoration: none;
}
.post-title {
align-items: baseline;
display: flex;
flex-wrap: wrap;
gap: 0 4rem;
margin-bottom: var(--body-item-spacing);
}
.post-title h1 {
@ -511,6 +491,58 @@ ol ol {
padding: 0 0.5rem;
}
footer > .tags {
display: flex;
padding-inline-start: 0;
}
footer > .tags > li {
background-color: var(--tag-background-color);
color: var(--tag-foreground-color);
border-radius: 4px;
display: inline-block;
font-size: 75%;
letter-spacing: 1px;
}
footer > .tags > li:hover {
background-color: var(--tag-hover-background-color);
}
footer > .tags > li > a {
color: inherit;
display: block;
height: 100%;
width: 100%;
padding: 0.6rem 1rem;
}
footer > .tags > li > a:hover {
color: var(--tag-hover-foreground-color);
text-decoration: none;
}
footer > .tags > li + li { margin-inline-start: 1rem; }
footer > .tags > li.chevron + li { margin-inline-start: 0 }
footer > .tags > .chevron {
align-items: center;
border: 0;
border-radius: 0;
color: var(--tag-spacer-foreground-color);
background-color: inherit;
display: flex;
justify-content: center;
margin-inline-start: 0;
padding-inline-start: 1px;
width: 2rem;
}
footer > .tags > .chevron:hover {
color: var(--tag-spacer-foreground-color);
background-color: inherit;
}
.youtube iframe {
aspect-ratio: 16 / 9;
margin-bottom: -3px;