Create shortcode for image legends (as ul list)

Because it’s moving to Hugo from WordPress, I need to create a shortcode to display legends under some of the images illustrating a site that were previously displayed in a page with just html and css. A typical example would be this:

The code to do this is:

1. html

<ul class="legend">
<li class="blue"> National recognition of animal sentience</li>
<li class="green"> Partial recognition of animal sentience<sup>1</sup></li>
<li class="yellow"> National recognition of animal suffering</li>
<li class="orange"> Partial recognition of animal suffering<sup>2</sup></li>
<li class="red"> No recognition of animal sentience or suffering</li>
<li class="grey"> Unknown</li>
<li class="none"><sup>1</sup>&nbsp;certain animals are excluded, only mental health is acknowledged, and/or the laws vary internally</li>
<li class="none"><sup>2</sup>&nbsp;only includes domestic animals</li>
</ul>

2. css

.legend {
  list-style: none;
  text-align: left;
  width: 20em;
  margin: 0 auto
}

.legend li {
  line-height: 1;
  margin: 0
}

.legend li::before {
  font-size: 1.5em;
  content: "\25A0"
}

.legend .blue::before {
  color: #000cff
}

.legend .green::before {
  color: #74d218
}

.legend .yellow::before {
  color: #eed402
}

.legend .orange::before {
  color: #f57900
}

.legend .red::before {
  color: #cd0001
}

.legend .grey::before {
  color: #e0e0e0
}

.legend .none {
  font-size: .83em;
  margin: .75em 0 .75em -1.5em
}

.legend .none::before {
  color: #fff;
  content: ""
}

The above is just one example: needs might vary compared with this and, in particular, one wouldn’t know in advance how many items one would need to set for each legend created using the shortcode, although one would have to choose between the available colours (blue, green, yellow, orange, grey). A further refinement would be to allow the user to set his own colours, but I think it makes more sense to set those using the :root.

One would also need to include a separate list for explanatory items, that are included in the ul as individual li elements, but are rendered differently by the css.

Any suggestions would be most welcome.

Why? The simplest option is to just enable unsafe HTML rendering in Goldmark and drop your existing html into your .md file.

    [markup.goldmark.renderer]
      unsafe = true

I know that, but like to keep my code clean.

Since legends are often generated from data, it might make sense to store the legend data (json, toml, or yaml) adjacent to the imageβ€”both as page resources.

content/
└── posts/
    └── post-1/
        β”œβ”€β”€ images/
        β”‚   β”œβ”€β”€ a.jpg
        β”‚   β”œβ”€β”€ a.json  <-- legend data
        β”‚   β”œβ”€β”€ b.jpg
        β”‚   β”œβ”€β”€ b.json  <-- legend data
        β”‚   └── c.jpg   <-- this image has no legend, and that's OK
        └── index.md

markdown

{{< foo "images/a.jpg" >}}

{{< foo "images/b.jpg" >}}

{{< foo "images/c.jpg" >}}
layouts/shortcodes/foo.html (something like...)
{{ with $path := .Get 0 }}
  {{ with $.Page.Resources.Get . }}
    <figure>
      <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}" alt="">
      {{ $legendData := print (strings.TrimSuffix (path.Ext $path) $path) ".json" }}
      {{ with $.Page.Resources.Get $legendData }}
        <figcaption>
          <ul class="legend">
            {{ range unmarshal . }}
              <li class="{{ .class }}">{{ .description }}</li>
            {{ end }}
          </ul>
        </figcaption>
      {{ end }}
    </figure>
  {{ else }}
    {{ errorf "The %q shortcode was unable to get %q. See %s" $.Name . $.Position }}
  {{ end }}
{{ else }}
  {{ errorf "The %q shortcode requires a single positional parameter. See %s" .Name .Position }}
{{ end }}


content/posts/post-1/images/a.json
[
  {
    "class": "blue",
    "description": "National recognition of animal sentience"
  },
  {
    "class": "green",
    "description": "Partial recognition of animal sentience"
  }
]

5 Likes

The perfect, elegant solution. Thank you very much.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.