My Little Corner of the Net

Simple Image Galleries With Eleventy

As I continue converting my largest non-work site from Jekyll to Eleventy, I keep coming across things that I did in Jekyll that no longer work in Eleventy.  One of these is image galleries.

Jekyll and Eleventy have a fundamentally different approach to how they handle files.  Jekyll splits all of the files in the project folder into two types, based on whether or not they contain front matter.  Files with front matter are transformed and the result is saved to the site folder.  Files without front matter (which includes all images, PDFs, JavaScript, CSS, etc.) are simply copied to the site.  The latter, which Jekyll refers to as “static files” are placed into a static_files collection which can be accessed in templates.  I was able to use this collection to make simple photo galleries.

First, I created a gallery.html layout that looked something like this:

{{ content }}

<div class="gallery">
  {% for image in site.static_files %}
    {% if image.path contains page.gallerydir %}
      <div class="gallery-image"><a href="{{ image.path }}" class="gallery-link"><img src="{{ image.path }}"></a></div>
    {% endif %}
  {% endfor %}
</div>

Then, for each gallery page, I’d add a markdown file with a gallerydir variable in my front matter set to the path of the directory containing my gallery images:

---
title: Big Event Photos
layout: gallery
gallerypath: events/images/big-event
---

Check out some photos from our Big Event!

When the page is processed, the template code loops through the entire static_files collection, checks whether the path of each file falls within the gallerydir, and if so, links to it in the output.  I use a lightbox script (GLightbox, in this specific case) to allow the user to browse the images in a pleasing way.

Eleventy doesn’t have this concept of static files.  Eleventy only processes the types of files you tell it to look at and ignores everything else.  If you want Eleventy to copy static files, you have to tell it to do so by using eleventyConfig.passthroughFileCopy() or something similar.  While this will get the files into your site, they won’t be automatically added to any collections.

To build the list of gallery images, and keep them separate from the rest of the site’s images, I moved all of the gallery images into a “galleries” directory.  Within that I created subdirectories of images for each gallery.  Then I used the NodeJS package fast-glob to find those files.

First, fast-glob has to be installed:

npm install --save-dev fast-glob

Then, it needs to be imported within .eleventy.js:

const fastglob = require("fast-glob")

And then we call it from inside the module.exports routine within .eleventy.js to build a list of our gallery images:

const galleries = fastglob.sync(["**/galleries/*/*.*", "!_site"])

This sucks the paths of any file that has the parent directory structure of galleries/{some gallery name} into an array. (The second parameter, !_site, tells fast-glob to ignore any file paths that are already copied to the _site directory; flast-glob doesn’t understand the Eleventy file structure, so it doesn’t know to ignore _site.)  To actually use it, we need to create a new Eleventy collection. To do that, we also add this to module.exports:

eleventyConfig.addCollection("galleries", function (collection) {
    let items = galleries.map((x) => {
        let paths = x.split("/")
        return {
            gallery: parts[parts.length - 2],
            path: x,
            name: [parts.length -1]
        }
    })
    return items
})

This takes the list of image paths and turns it into a set of objects with three properties: gallery (the name of the gallery the image is within, pulled from the last directory name in the path), path (the original path of the image), and name (the filename of the image, which I’m not actually using right now, but I figured my be useful to know in the future).  This list of objects is used to populate a new “galleries” collection in Eleventy.

With this new collection, I can update my gallery layout to look more like this:

{{ content }}

<div class="gallery">
    {% assign images = collections.galleries | where: "gallery", gallery %}
    {% for images in images %}
        <div class="gallery-image"><a href="{{ image.path }}" class="gallery-link"><img src="{{ image.path }}"></a></div>
    {% endfor %}
</div>

And in my page’s front matter, I replace gallerypath with gallery, and assign it the name of the gallery (i.e. the directory name within one of my site’s “galleries” directories) I want to show:

---
title: Big Event Photos
layout: gallery
gallery: big-event
---

Check out some photos from our Big Event.

it’s important to note that fast-glob only returns a list of files that match the pattern, it does not copy them to the site automatically.  In my case, an existing passthroughFileCopy() for all JPEG images does the trick,  but we could also update the map function inside the addCollection() to handle this if we wanted.  As a future extension to this concept, I may look at using Eleventy’s Image plugin to automatically resize my images to ideal dimensions, but in my current use case, all of my images have already been manually resized.

So that’s how it did it.  This method gets me to feature parity on the Eleventy site, it still needs some work.  As it stands now, neither the Jekyll or the Eleventy solution is accessible.  I need a way to add additional information, like alt text for the images, to the galleries.  The obvious solution is probably to add a CSV file to the site’s _data directory to store this information, but then I could just loop through that instead of using the file glob, so maybe this whole approach isn’t really needed at all.  We shall see.

Leave a Reply

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

<