diff --git a/Makefile b/Makefile
index a7f7a16..95a71eb 100644
--- a/Makefile
+++ b/Makefile
@@ -4,3 +4,6 @@ test:
build:
@echo "Building site"
@hugo build
+
+deploy: build
+ @scp -r public/* server.local.bitard.fr:~/blog/
\ No newline at end of file
diff --git a/content/post/2025-03-30-welcome-gemini.md b/content/post/2025-03-30-welcome-gemini.md
new file mode 100644
index 0000000..e7fc312
--- /dev/null
+++ b/content/post/2025-03-30-welcome-gemini.md
@@ -0,0 +1,49 @@
+---
+categories:
+- software
+date: "2025-03-30T00:00:00Z"
+tags: ["software"]
+title: Publishing this blog on Gemini
+summary: Using Hugo
+---
+
+TLDR: I have [my blog][blog_gemini] published on gemini.
+You can look at my [Pull request][pull_request] if you want to copy/paste the code for Hugo.
+
+I've looked at [Gemini][gemini] for quite a while, and I wanted to use it for this blog.
+Some time ago I used Jekyll and could not found any resource on how to create gemini files from jekyll.
+
+I switched to Hugo some time ago and I tried to output to gemtext, without success.
+
+This time I really gave it a try and I think I found a nice setup.
+
+I relied on 2 blog posts I found, the first one by [Sylvain Durand][sylvaindurand] and the second one by [Brain baking][brainbaking]
+
+These resources were quite outdated, they both gave up on gemini after quite some time, which I can understand but at the same time makes me sad.
+
+## Main issue
+
+My biggest problem is the conversion of links into a Gemtext compatible format.
+For those who use the inline syntax (brackets+parentheses), that's pretty straightforward, but I use the markdown indirections, where all my links are at the bottom of the document.
+
+
+First I had to create a map containing all the key/url pairs.
+Then replace every link in my document with a reference number.
+And finally, display all the references at the end of the document.
+
+## Build and serve
+
+You can have a look at this [pull request][pull_request] to glue this together, then you can build and deploy.
+
+Building is as easy as typing `hugo build`.
+To deploy, I used [Agate][agate] server, with the docker image it's as easy as `docker run --name gemini -d --restart unless-stopped -p 1965:1965 -v /path_to_public_folder/:/gmi:ro -v /path_to_certs:/certs ghcr.io/mbrubeck/agate:3.3.14 --hostname blog.bitard.fr`
+
+From now one, I should by able to publish both on the web and on Gemini \o/
+
+
+[agate]: https://github.com/mbrubeck/agate
+[blog_gemini]: gemini://blog.bitard.fr
+[pull_request]: https://github.com/agileek/agileek.github.io/pull/3
+[gemini]: https://geminiprotocol.net/
+[sylvaindurand]: https://sylvaindurand.org/gemini-and-hugo/
+[brainbaking]: https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/
diff --git a/hugo.toml b/hugo.toml
index afef130..5fe0748 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -5,15 +5,17 @@ languageCode = "en-us"
title = "Software"
enableRobotsTXT = true
sectionPagesMenu = 'main'
+summaryLength = 0
[pagination]
pagerSize = 200
[outputs]
-home = ["HTML", "RSS", "JSON"]
+home = ["HTML", "RSS", "JSON", "GEMINI", "GEMINI_RSS"]
+page = ["HTML", "GEMINI"]
[params]
-env = "production" # to enable google analytics, opengraph, twitter-cards and schema.
+env = "production"
description = "Yet another blog on software stuff"
author = "Michaël Bitard"
@@ -32,7 +34,7 @@ ShowPageNums = true
ShowToc = true
comments = false
images = ["images/home.png"]
-hideAuthor=true
+hideAuthor = true
# homeInfoParams.Title="PaperMod's Demo"
# homeInfoParams.Content="👋 Welcome to demo page of Hugo's theme PaperMod!"
[params.editPost]
@@ -43,9 +45,28 @@ appendFilePath = true # to append fi
text = "Yet another blog on software stuff"
[markup.goldmark.renderer]
- unsafe = true
+unsafe = true
# FIXME add asciinema
# FIXME Languages
# [[module.imports]]
# path= "https://github.com/hybras/hugo-asciinema"
+[mediaTypes]
+[mediaTypes.'text/gemini']
+delimiter = '.'
+suffixes = ['gmi']
+
+[outputFormats]
+[outputFormats.GEMINI]
+baseName = 'index'
+isHTML = false
+isPlainText = false
+mediaType = 'text/gemini'
+protocol = "gemini://"
+permalinkable = true
+
+[outputFormats.GEMINI_RSS]
+baseName = 'feed'
+isPlainText = false
+mediaType = 'application/rss+xml'
+protocol = "gemini://"
diff --git a/layouts/_default/single.gmi b/layouts/_default/single.gmi
new file mode 100644
index 0000000..a9a6042
--- /dev/null
+++ b/layouts/_default/single.gmi
@@ -0,0 +1,77 @@
+# {{ .Title | plainify }}
+
+{{- $scratch := newScratch }}
+{{- $content := .RawContent -}}
+{{- $content := $content | replaceRE `#### ` "### " -}}
+{{- $content := $content | replaceRE `\\\n` "\n" -}}
+{{- $content := $content | replaceRE `\n- (.+?)` "\n* $1" -}}
+{{- $content := $content | replaceRE `\n(\d+). (.+?)` "\n* $2" -}}
+{{- $content := $content | replaceRE `
` "\n" -}}
+{{- $content := $content | replaceRE `(.+?)` "[$2]($1)" -}}
+{{- $content := $content | replaceRE `{{ youtube (.+?) >}}` "=> https://www.youtube.com/watch?v=$1 YouTube Video link to $1" -}}
+{{- $content := $content | replaceRE "([^`])<.*?>([^`])" "$1$2" -}}
+{{- $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
+{{- $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
+{{- $links := findRE `\n=> ` $content }}{{ $scratch.Set "ref" (add (len $links) 1) }}
+{{- $refs := findRE `\[.+?\]\(.+?\)` $content }}
+{{- $scratch.Set "content" $content }}
+{{- /* Get 'simple links' */}}
+{{- range $refs }}
+ {{- $ref := $scratch.Get "ref" }}
+ {{- $contentInLoop := $scratch.Get "content" }}
+ {{- $url := (printf "%s #%d" . $ref) }}
+ {{- $contentInLoop := replace $contentInLoop . $url -}}
+ {{- $scratch.Set "content" $contentInLoop }}
+ {{- $scratch.Set "ref" (add $ref 1) }}
+{{- end }}
+{{- $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" -}}
+{{- $linksValue := findRESubmatch `\[([^^:\]]*)\]:[ ]*(.+)\n` $content }}
+{{- $scratch.Set "content" $content }}
+{{- range $linksValue }}
+ {{- $contentInLoop := $scratch.Get "content" }}
+ {{- $scratch.Set (index . 1) (index . 2) }}
+ {{- $contentInLoop := replace $contentInLoop (index . 0) "" -}}
+ {{- $scratch.Set "content" $contentInLoop }}
+{{- end }}
+{{- $imagesMD := findRESubmatch `!\[([^^]+?)\]\[(.+?)\]` $content }}
+{{- range $imagesMD }}
+ {{- $contentInLoop := $scratch.Get "content" }}
+ {{- $url := (printf "" (index . 1) ($scratch.Get (index . 2) )) }}
+ {{- $contentInLoop := replace $contentInLoop (index . 0) $url -}}
+ {{- $scratch.Set "content" $contentInLoop }}
+{{- end }}
+{{- $content := $scratch.Get "content" -}}
+{{- $content := $content | replaceRE `\n\n!\[.*\]\((.+?) \"(.+?)\"\)` "\n\n=> $1 Image: $2" -}}
+{{- $content := $content | replaceRE `\n\n!\[.*]\((.+?)\)` "\n\n=> $1 Embedded Image: $1" -}}
+{{- $linksMD := findRESubmatch `\[([^^]+?)\]\[(.+?)\]` $content }}
+{{- $scratch.Set "content" $content }}
+{{- range $linksMD }}
+ {{- $ref := $scratch.Get "ref" }}
+ {{- $contentInLoop := $scratch.Get "content" }}
+ {{- $url := (printf "%s[%d]" (index . 1) $ref) }}
+ {{- $contentInLoop := replace $contentInLoop (index . 0) $url -}}
+ {{- $scratch.Set "content" $contentInLoop }}
+ {{- $scratch.Set "ref" (add $ref 1) }}
+{{- end }}
+{{- $content := $scratch.Get "content" -}}
+{{ $content | safeHTML }}
+
+---
+## References
+{{- $scratch.Set "ref" (add (len $links) 1) }}
+{{- range $refs }}
+{{- $ref := $scratch.Get "ref" }}
+{{- $url := (printf "%s #%d" . $ref) }}
+=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1 ($2)" -}}
+{{- $scratch.Set "ref" (add $ref 1) }}
+{{- end}}
+{{- range $linksMD }}
+{{- $ref := $scratch.Get "ref" }}
+{{- $url := (printf "%s #%d" (index . 1) $ref) }}
+=> {{ $scratch.Get (index . 2) }} [{{ $ref }}] {{ index . 1}} ({{ $scratch.Get (index . 2) }})
+{{- $scratch.Set "ref" (add $ref 1) }}
+{{- end}}
+---
+
+=> / Back to the Index
+=> https://agileek.github.io{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} View this article on the WWW
diff --git a/layouts/index.gemini_rss.xml b/layouts/index.gemini_rss.xml
new file mode 100644
index 0000000..ae65bba
--- /dev/null
+++ b/layouts/index.gemini_rss.xml
@@ -0,0 +1,22 @@
+
+
+ {{ .Site.Title }}
+ {{ i18n "description" }}
+ {{ (replace .Permalink "https://" "gemini://") | safeURL }}
+
+ {{- if .IsHome }}
+ {{- $pages := union .RegularPages .Sections }}
+ {{- $pages = where site.RegularPages "Type" "in" site.Params.mainSections }}
+ {{- $pages = where $pages "Params.hiddenInHomeList" "!=" "true" }}
+ {{- $paginator := .Paginate $pages }}
+ {{- range $paginator.Pages }}
+ -
+ {{ .Title | plainify }}
+ {{ (replace .Permalink "https://" "gemini://") | safeURL }}
+ {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}
+ {{ (replace .Permalink "https://" "gemini://") | safeURL }}
+
+ {{ end }}
+ {{ end }}
+
+
\ No newline at end of file
diff --git a/layouts/index.gmi b/layouts/index.gmi
new file mode 100644
index 0000000..a40d4aa
--- /dev/null
+++ b/layouts/index.gmi
@@ -0,0 +1,17 @@
+## Navigation
+
+{{ range .RegularPages }}
+=> {{ .RelPermalink }} {{ .Title | plainify }}
+{{- end }}
+
+## List of posts
+
+{{- if .IsHome }}
+ {{- $pages := union .RegularPages .Sections }}
+ {{- $pages = where site.RegularPages "Type" "in" site.Params.mainSections }}
+ {{- $pages = where $pages "Params.hiddenInHomeList" "!=" "true" }}
+ {{- $paginator := .Paginate $pages }}
+ {{- range $index, $page := $paginator.Pages }}
+=> {{ .RelPermalink }} {{ .Title | plainify }}{{ if gt (len .Summary) 0 }} - {{ .Summary | plainify | htmlUnescape }}{{ end }} ({{ .Date.Format ((default "2006/01/02" site.Params.DateFormat)) }})
+ {{- end }}
+{{- end }}