Simple Image Gallery Using Gridsome

18 Jul 2020

This portfolio site I'm building needs a gallery of lettering images. I haven't found a specific tutorial for this use case. After googling for a while I found this Stackoverflow answer, it's for Nuxt but I tought it might work for Gridsome too.

So I'm documenting the process and sharing it with others who might want to do similar thing. Note this is a simple implementation that utilizes Webpack feature instead of GraphQL.

In my case, I'll be making the gallery under /lettering URL, so I'm making new file on /pages/Lettering.vue. There's two part of this: the page itself, and gallery of images. I'll be putting the image on ./static/images/lettering/.... It looks like this in directory structure: (other files ommited)

๐Ÿ“ฆproject-name
 โ”œโ”€๐Ÿ“‚src
 โ”‚ โ””โ”€๐Ÿ“‚pages
 โ”‚ โ”‚ โ””โ”€๐Ÿ“œLettering.vue
 โ”‚ โ””โ”€...
 โ”œโ”€๐Ÿ“‚static
 โ”‚ โ””โ”€๐Ÿ“‚images
 โ”‚ โ”‚ โ””โ”€๐Ÿ“‚lettering
 โ”‚ โ”‚ โ”‚ โ””โ”€ (image files goes here)
 โ”œโ”€ ...

I also introduce name template for the image files here: image-name_YY-MM-DD.jpg. I'm doing this so I can sort the images by Date later. You can change the name template to your liking.

Here's what goes into actual page Lettering.vue:

<template>
  <Layout>
    <h1 class="text-4xl lg:text-6xl uppercase leading-none mb-4">Lettering</h1>
    <div class="flex flex-wrap pb-20 -mx-3">
      <div class="w-full sm:w-1/2 md:w-1/3 lg:w-1/4" v-for="(image, index) in sortedImages" :key="index">
        <div class="px-3 my-3">
          <div class="relative shadow-lg" style="padding-bottom: 100%">
            <g-image class="absolute w-full h-full object-cover"
              :src="image.pathLong" :title="`20${image.year}-${image.month}-${image.day}`"/>
          </div>
        </div>
      </div>
    </div>
  </Layout>
</template>

<script>
export default {
  metaInfo: {
    title: 'Lettering'
  },
  data() {
    return {
      images: []
    }
  },
  mounted() {
    this.importAll(require.context('../../static/images/lettering/', true, /\.jpg$/))
  },
  computed: {
    sortedImages() {
      return this.images.sort((a, b) => (
        new Date(`20${b.year}`, b.month, b.day) -
        new Date(`20${a.year}`, a.month, a.day)
      ))
    }
  },
  methods: {
    importAll(r) {
      r.keys().forEach(key => (this.images.push({
        pathLong: r(key),
        pathShort: key,
        year: key.split('_').pop().replace('.jpg', '').split('-')[0],
        month: key.split('_').pop().replace('.jpg', '').split('-')[1],
        day: key.split('_').pop().replace('.jpg', '').split('-')[2],
      })))
    }
  },
}
</script>

To import all the images, we are utilizing webpack require.context inside the image directory. Then for each image, we put them into images array as an object with few attributes: pathLong, year, month, day. You can optimize or change the code to your liking, but for now it works okay.

I'm also using tailwind CSS here, with a minor rule breaking inline style for padding-bottom trickery to get that square div ratio.

Hope this helps! Thanks for reading.

Built with ๐Ÿ’– using Gridsome