Generating a Book Bingo Chart in Hugo

Another r/Fantasy 2021 Book Bingo post! How in the world am I generating this (updating) chart in Hugo?

2021 Book Bingo

SFF anthology or collection

Attack on Titan, Vol. 1

Set in Asia (Hard: by an Asian author)

r/Fantasy A to Z Genre Guide (Hard: by a BIPOC author)

Found Family (Hard: featuring an LGBTQ+ character)

First person POV (Hard: Multiple)

r/Fantasy Book Club (Hard: with participation)

New to you author (Hard: haven’t heard much about)

Gothic Fantasy (Hard: not in the Book Riot article)

Mexican Gothic

(Hard Mode)

Backlist book (Hard: published before 2000)

Revenge-seeking character (Hard: revenge as the major book plot)

Mystery plot (Hard: not primary world urban fantasy)

Six Wakes

(Hard Mode)

Comfort read (Hard: that isn’t a reread)

Wild Sign

(Hard Mode)

Debut novel (Hard: published in 2021)

Tales of Nezura: Book 1: The Zevolra

(Hard Mode)

Cat squasher (500+ pages; Hard: 800+ pages)

SFF-related nonfiction (Hard: published in the last 5 years)

Latinx or Latin American author (Hard: with fewer than 1000 Goodreads ratings)

Self published (Hard: with fewer than 50 Goodreads ratings)

Tales of Nezura: Book 1: The Zevolra

(Hard Mode)

Forest setting (Hard: for the entire book)

Annihilation

(Hard Mode)

Genre mashup (Hard: of three or more genres)

Gideon the Ninth

(Hard Mode)

Has chapter titles of more than one word (Hard: for every chapter)

The Midnight Library

(Hard Mode)

___ of ___ (Hard: and ___)

First contact (Hard: that doesn’t lead to war)

Project Hail Mary

(Hard Mode)

Trans or Nonbinary (Hard: protagonist)

Debut author (Hard: with an AMA)

Witches (Hard: as the main protagonist)

A Great and Terrible Beauty

(Hard Mode)

To start, I have a Data file for the names of the categories:

- 
  - "SFF anthology or collection"
  - "Set in Asia (Hard: by an Asian author)"
  ...
- 
  - "r/Fantasy Book Club (Hard: with participation)"
  ...
...

It’s just markdown (for links) in a nested list. 5x5 (hard coded) at the moment, but I could probably make that flexible if I wanted.

Next, I have to add a bit of metadata to each post that’s going to be included in a Book Bingo:

bingo:
- 2021 Book Bingo
bingo-data:
    2021 Book Bingo: [3x1+]

It’s a bit annoying that I have to do this. What I’d really want is for the Taxonomy to support a hash as the data field, so I could just do:

bingo:
    2021 Book Bingo: [3x1+]

But if you do that, the post isn’t included in the bingo taxonomy. So I have to include both. If I figure out a better way to do that, I’ll update this post, but for the moment, it’s okay. So bingo is a Taxonomy (so I can list all pages that match it without cycling through all pages), while bingo-data is just a $Page.Param that I can access. The field is: {row}x{column}{hard mode flag}.

Finally, I actually make a shortcode that can use that information and build a table:

{{- $title := .Get 0 -}}
{{- $slug := $title | urlize }}
{{- $data := index $.Site.Data.bingo $title -}}

<h1>{{ $title }}</h1>

<table class="bingo">
    {{- range $row := seq 0 4 -}}
    <tr>
        {{- range $col := seq 0 4 -}}
        <td>
            {{- $index := (printf "%dx%d" (add 1 $row) (add 1 $col) )}}
            {{- $indexHard := (printf "%dx%d+" (add 1 $row) (add 1 $col) )}}
            {{- $title := index $data $row $col }}

            <p>{{ $title | markdownify }}</p>
            
            {{- range $page := index $.Site.Taxonomies "bingo" $slug -}}
                {{- $squares := index $page.Params "bingo-data" (replace $slug "-" " ") -}}
                {{- if (or (in $squares $index) (in $squares $indexHard)) -}}
                    <a href="{{ $page.Permalink }}">
                        <figure>
                            {{ safeHTML (index (findRE "(?m:<img.*?>)" .Content 1) 0) }}
                            <figcaption>{{ .Title }}</figcaption>
                        </figure> 
                    </a>
                    {{- if in $squares $indexHard -}}
                    <p>(Hard Mode)</p>
                    {{- end -}}
                {{- end -}}
            {{- end -}}
        </td>
        {{- end -}}
    </tr>
    {{- end -}}
</table>

  • range over the rows and columns, building an HTML table
  • In each cell:
    • Include the title of the cell from the data page
    • Build a index (and indexHard) for that row and column
    • Search over all pages in the matching Taxonomy, use the Page Data to see if they match this specific index or not
    • If so, include the cover as a link, plus the ‘(Hard Mode)’ flag

I’ll admit, it feels a bit hacky, but one of the beautiful things about a static site generator is that it only has to run when rebuilding my site. The end result is just HTML. And I only have to update the individual pages, not keep a central list. I think that’s pretty neat.

Perhaps I should figure out more things I can do with Page Data. Perhaps keep track of authors as well as series? Ratings? Who knows!