published on 24.01.2021

Some time ago, I wanted to display images in a better way on my Hugo website. I searched for existing Hugo themes for photography and gallery tags. Can’t say I find much. Then, I met a javascript library called nanogallery2 which is using another javascript library as an image viewer lightbox2. In this post, I’ll explain how I used nanogallery2 on my Hugo website. I assume that you know about image processing in Hugo or read my previous post.

Use LightBox in a Post

Lightbox2 is a javascript library developed by Lokesh Dhakar. It displays images and videos in a good looking way. NanoGallery2 is another library, it uses lightbox2 as image viewer and, additionaly, has other features.

To use an image in a post I have created a shortcode called named img: /layouts/shortcodes/img.html. You can see the whole img shortcode at the end of the post but I’ll continue by taking only the related part with nanogallery2:

{{ $image = resources.GetMatch (.Get "src") }}
{{ $.Scratch.Set "thumbnail" ($image.Resize "600x q90") }}
<img src="{{ ($.Scratch.Get "thumbnail").RelPermalink }}" data-ngsrc="{{$image.RelPermalink}}" alt="{{ $caption }}"/>
  • We get the resource $image.
  • Create a smaller one and call it thumbnail.
  • Pass the original image we want to display as data-ngsrc.

You can see the original concept from nanogallery2 documentation

Additionaly, we can change the default settings by providing data-nanogallery2-lightbox. The settings should be in json format, you can directly add the parameters you want into html or keep the settings in a separate file and pass it to the HTML using Hugo’s getJSON function. To learn about the settings, you must read the nanogallery2’s documentation.

{{ $nanogallery2_settings := getJSON "/static/ng2_lightbox.json" | jsonify}}

<img src="{{ ($.Scratch.Get "thumbnail").RelPermalink }}" data-ngsrc="{{$image.RelPermalink}}" 
data-nanogallery2-lightbox="{{$nanogallery2_settings}}" alt="{{ $caption }}"/>

Click on the image to see lightbox in action.

Village of Sekiya at Sumida River
Village of Sekiya at Sumida River

Use NanoGallery2

This is probably not very useful for a blog post we can use the gallery view too. To do that, I’ve created a separate shortcode called gallery.html. This one takes a directory and displays the resources under that directory.

You can call the gallery shortcode like this: {{/< gallery directory="images/posts/nanogallery/*" >}} Don’t forget the star at the end, read the pattern matching for more info.

images/posts/nanogallery/IMG_20190702_155840 (Large).jpg [ images/posts/nanogallery/IMG_20190702_160055 (Large).jpg [ images/posts/nanogallery/IMG_20190702_160231 (Large).jpg [ images/posts/nanogallery/IMG_20190925_083347 (Large).jpg [ images/posts/nanogallery/IMG_20200106_113749 (Medium).jpg [ images/posts/nanogallery/IMG_20200106_113826 (Medium).jpg [ images/posts/nanogallery/IMG_20200106_113902 (Medium).jpg [ images/posts/nanogallery/IMG_20200106_115825 (Medium).jpg []

Recently, as a weekend project, I’ve created an image gallery site for myself. I’ve published the project on GitLab: Art-Collection Theme. It’s pretty simple, and probably requires some improvements. I learned a lot while building it. It’s designed to present just collection of images only, and displaying blog content is disabled.

The Libraries

To use the libraries, we have to load them, usually in the head section of the HTML. Jquery is a dependency of nanogallery2, so we have to add it too.

{{ if }}
    <script src=""></script>
    <link rel="stylesheet" href=""/>
    <script src=""></script>
{{ end }}

You should set gallery: true in the page’s front-matter, in order to load these scripts. Otherwise, they won’t be loaded. This is just a small trick for not adding the libraries to all the pages if we are not going to use them.

{{ $nanogallery2_settings := getJSON "/static/ng2_gallery_compact.json" | jsonify}}

<div data-nanogallery2="{{$nanogallery2_settings}}">
    {{ range $index, $image := sort (resources.Match (.Get "directory")) }}
    {{ $.Scratch.Set "thumbnail" ($image.Resize "x300 q90") }}
    <a href="{{ $image.RelPermalink }}" data-ngthumb="{{ ($.Scratch.Get "thumbnail").RelPermalink }}">{{$image.Name}}</a>
    [{{ end }}]

img shortcode

I used <figure> instead of <img> alone to be able to add caption when necessary. The shortcode seems long but what it does is actually simple.

  • It takes an image, checks it’s size
  • If the image is bigger than 600x450,
  • Then, it resize the image as 600x width or x450 height, based on the image rotation and protects the aspect ratio.
  • Use the smaller image in post and sets the original image as a link (so we may show it on full quality on click).
    - src: image path [required]
    - class: center, right, left
    - width: width for image (example: 400px, 20%)
    - caption: text for caption
    - alt: alt text for the image (caption will be used if not specified)
    - link: href on caption

{{ $class :=  or (.Get "class") "center" }}
{{ $image = resources.GetMatch (.Get "src") }}
{{ $caption := "" }}

{{/* Generate Thumbnail */}}
{{ if ge $image.Width $image.Height }}
{{ if ge $image.Width "600" }}
    {{ $.Scratch.Set "thumbnail" ($image.Resize "600x q90") }}
{{ else}}
    {{ $.Scratch.Set "thumbnail" $image }}
{{ end }}
{{ else }}
{{ if ge $image.Height "450" }}
    {{ $.Scratch.Set "thumbnail" ($image.Resize "x450 q90") }}
{{ else }}
    {{ $.Scratch.Set "thumbnail" $image }}
{{ end }}
{{ end }}

{{ if (.Get "caption") }}
    {{ $caption = (.Get "caption" | markdownify | plainify) }}
{{ else }}
    {{ $caption = (path.Split $image.Name).File }}
{{ end }}

{{ $nanogallery2_settings := getJSON "/static/ng2_lightbox.json" | jsonify}}

<figure class="{{ $class }}">
<img src="{{ ($.Scratch.Get "thumbnail").RelPermalink }}" data-ngsrc="{{$image.RelPermalink}}"
    alt="{{ $caption }}" {{ with .Get "width" }} width="{{.}}"{{ end }}/>
{{ with .Get "link" }}<a href="{{.}}">{{ end }}
{{ with .Get "caption" }}<figcaption>{{ $caption }}</figcaption>{{ end }}
{{ if .Get "link" }}</a>{{ end }}
You are reading the 19th of 19 episodes in Hugo.
Published on 24.01.2021 by Mert Bakır with commit 801c554.
#hugo #static-site
published on 10.07.2022

Previously, I’ve published a blog post about deploying static content on heroku with basic authentication. The main purpose was to get basic auth for a freely hosted static website. In that post, we hosted the source code on GitLab and configured a CI/CD pipeline to render the static content …

published on 28.05.2022

Each git commit has a field called Author which consists ‘’ and ‘’. We usually set these variables once, after installing git, with git config --global so that each repo gets the variables from the global definition. We can also set them locally for a …

published on 25.05.2022

In this post, I’ll first walk through hosting static content with basic authentication. Then, we’ll look into deploying to Heroku using GitLab Pipelines, more specifically deploying a certain sub-directory within the project instead of pushing the whole project. Also, I’ll share …

published on 17.04.2022
edited on 15.07.2022

Önceki bölümde, markdown formatını LaTeX formatına dönüştürmek için kullanılan Pandoc yazılımından bahsetmiştik. Şimdi konuyu bir adım daha ileri taşıyıp ve bookdown’a geçiyoruz. Bookdown; Rmarkdown kullanarak teknik dökümanlar, kitaplar yazabilmemizi sağlayan, Yihui Xie tarafından yazılmış …

published on 10.04.2022

I’ve been using WSL-2 on Windows for over a year. It’s very useful because some Python packages are just a headache to install on Windows. Also, docker. It’s just better on Linux. Yet, WSL-2 can also be problematic. I remember trying a dual-boot setup when things just went way too …

published on 03.03.2022

In this post, I’ll share how to install geopandas and some other gis related packages on Windows. If you are on Mac or Linux you can probably just pip install those without any issue. I usually had to do a google search every time I wanted to install these packages on Windows environment. Of …