💾 Archived View for sylvaindurand.org › gemini-and-hugo › index.gmi captured on 2022-04-28 at 17:50:59. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

sylvaindurand.org

Gemini and Hugo

For a few years, I have been using Hugo, a static site generator, to produce these pages. At the same time very fast and corresponding perfectly to my needs, it is above all very modular.

I was therefore not surprised to see that it was quite easy to convert, with little effort, my site for the Gemini protocol. This was not done without some tricks. Let's see how!

Declaring Gemini as an output format

Hugo can output content in multiple formats: most of them are already predefined, but it is also possible to create your own. This is what we are going to do for Gemini.

First, in the configuration file `config.yml` we will declare a new type `text/gemini` with the file suffix `.gmi`:

mediaTypes:
  text/gemini:
    suffixes:
      - "gmi"

Once this is done, we declare a new output format, which uses this type, which is given the name `GEMINI`.

outputFormats:
  GEMINI:
    name: GEMINI
    isPlainText: true
    isHTML: false
    mediaType: text/gemini
    protocol: "gemini://"
    permalinkable: true

Finally, it only remains to ask Hugo to generate pages for the different contents. For example, in my case:

outputs:
  home: ["HTML", "RSS", "GEMINI"]
  page: ["HTML", "GEMINI"]

To be able to generate the files, it is now necessary to create layouts to see how to display them!

Index page

To start with the index, we can start with `layout/index.gmi`. For example, here is a simple text, followed by a list of posts:

## List of posts

{{ range .RegularPages }}
=> {{ .RelPermalink }} {{ .Title }}
{{- end }}

Here, I sort the articles in descending chronological order, grouping them by date. This gives the following code:

## Posts grouped by year

{{ range .RegularPages.GroupByDate "2006" }}
### {{ .Key }}
{{ range .Pages.ByDate.Reverse }}
=> {{ .RelPermalink }} {{ .Title }}
{{- end }}
{{ end }}

Posts

For posts, we can create a `layout/_default/single.gmi`. Basically, it would suffice to display the title and content:

# {{ .Title }}

{{ .RawContent }}

Images

For images, I extract them with a simple regex and show them as a link:

{{- $content := .RawContent -}}
{{- $content = $content | replaceRE `\!\[(.+?)\]\((.+?)\)` "=> $2 Image: $1" }}
{{ $content }}

Links

For the links, I decided to simply not use inline links on the site, but only put the links on a single paragraph. This allows me, as before, a very simple regex:

{{- range findRE `\[.+?\]\(.+?\)` $content }}
    {{- $content = $content | replaceRE `\[(.+?)\]\((.+?)\)(.+)` "$1$3\n\n=> $2 $1 " }}
{{- end }}

However, this is not a very satisfactory method when you have a site that has a lot of links online. A solution, proposed by the site Brain Baking, allows you to reference each link with a number ([1], [2]...) and then to put the links underneath, automatically, thanks to a clever code:

Using Hugo to Launch a Gemini Capsule

Navigation to other pages

If you want to add links for previous and next articles with:

{{ if .Next }}=> {{ .Next.RelPermalink }} ← Newer: {{ .Next.Title }}{{ end }}
{{ if .Prev -}}=> {{ .Prev.RelPermalink }} → Older: {{ .Prev.Title }}{{- end }}

Feeds

To create RSS feeds, we can create a new output format, then define its layout.

RSS

We will do the same here! In `config.yml`, we define:

outputFormats:
  GEMINI_RSS:
    baseName: "feed"
    mediaType: "application/rss+xml"
    isPlainText: false

outputs:
  home: ["HTML", "GEMINI", ..., "GEMINI_RSS"]

Then, we create `layouts/index.gemini_rss.xml` with the following content:

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>{{ .Site.Title }}</title>
    <description>{{ i18n "description" }}</description>
    <link>{{ (replace .Permalink "https://" "gemini://") | safeURL }}</link>
    <atom:link href="{{ .Permalink | safeURL }}feed.xml" rel="self" type="application/rss+xml" />
    {{- range .RegularPages }}
    <item>
      <title>{{ .Title }}</title>
      <link>{{ (replace .Permalink "https://" "gemini://") | safeURL }}</link>
      <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
      <guid>{{ (replace .Permalink "https://" "gemini://") | safeURL }}</guid>
    </item>
    {{ end }}
  </channel>
</rss>

The RSS feed is now available on `/feed.xml`.

Export

I use `rsync` to easily export my files to the server:

hugo

rsync -avz --no-perms --no-owner --no-group \
      --no-times --delete public/ vps:/var/gemini

rm -rf public

This last folder is then read by a gemini server, as explained in the previous article:

Discovering the Gemini protocol