Over the course of my career as a front-end developer, I built several open-source tools to make my life easier. This color palette generator is one of them. In this article, I will explain how you too can build a color palette generator using Nuxt and Vuetify.

Why a Color Palette Generator?

I created this tool because I no longer wanted to waste time searching for a nice color palette every time I needed one. I wanted something where I could pick a color - at random or not - and generate a color palette right away. That's what this generator does. Click here to get an idea of what the end result will look like.

Why Nuxt?

Nuxt is an outstanding tool developed on top of Vue. It makes it easier to create universal apps that can execute on both client- and server-side, because it gives us methods like asyncData and because it provides access to properties like isClient or isServer.

The framework has awesome tooling too, so the development process is very enjoyable, and Nuxt works well enough for a project that should be SEO-friendly.

Prerequisites

  • Knowledge in HTML, CSS, and JavaScript
  • Basic knowledge of Vue.js
  • Some knowledge of Yarn or NPM

Step 1: Create a Nuxt Project

You can create a Nuxt project from npx or yarn. If you want the project structure to be built automatically, you can type the following:

npx create-nuxt-app color-palette-generator

or for Yarn:

yarn create nuxt-app color-palette-generator

But, for the sake of simplicity, I'll start a project from scratch. To begin with, you'll need an empty folder somewhere in your system:

mkdir x-team\palette-picker-generator

Navigate to palette-picker-generator this way:

cd .\x-team\palette-picker-generator

{
  "name": "palette-picker-generator",
  "scripts": {
    "dev": "nuxt"
  }
}

Install Nuxt with npm:

npm install --save nuxt

or for Yarn:

yarn add nuxt

Step 2: Create Your Folder Structure

Nuxt requires a strict structure for it to work (check that out here) so we'll need to create a pages folder:

mkdir pages

Navigate to pages:

cd pages

Create an index.vue file with the following code:

<template>
  <h1>Hello world!</h1>
</template>

Step 3: Run the Project

You can run the project with npm run dev or yarn dev. By default, Nuxt will run on localhost:3000. If the port is already in use, Nuxt will grab a random port to host the app.

To control that, you'll need to either kill the app running on 3000 or set another port. To do so, create a nuxt.config.js file (a pretty important config file - find out more here) in the root of the project with the following code:

export default {
  server: {
    port: 3333
  }
}

Step 4: Add Vuetify

Vuetify is an awesome components library widely used in many companies. It uses Material Design too, which is great. Implement it this way:

npm install @nuxtjs/vuetify -D

or with Yarn:

yarn add @nuxtjs/vuetify -D

Then, we'll update our nuxt.config-js file by adding the buildModules property:

export default {
  // some config above
  buildModules: ['@nuxtjs/vuetify']
  // some config below
}

Step 5: Add Code

Create the basic template to show a few cards with the nice colors you picked. In the template tags we previously created on pages/index.vue, you should insert:

<div v-for="(palette, index) in palettes" :key="index">
  <v-card
    v-for="color in palette.colors"
    :key="color"
    :style="{ backgroundColor: `#${color}` }"
  >
    <v-card-text>
      {{ color }}
    </v-card-text>
  </v-card>
</div>

As you can see, we have an array palettes that should contain an array of colors inside. Then we have a nested iteration with v-for to get the color that should be shown.

Now, let's create that palettes array. Here's how:

<script>
  import Vue from 'vue'

  export default Vue.extend({
    name: 'PalettePicker',
    data: () => ({
      palettes: [
        {
          name: 'Velvet',
          colors: ['EE4540', 'C72C41', '801336', '510A32', '2D142C']
        },
        {
          name: 'Sunset',
          colors: ['8FB9A8', 'FEFAD4', 'FCD0BA', 'F1828D', '765D69']
        }
      ]
    })
  })
</script>

We've created two palettes (called Velvet and Sunset) with their respective colors. This should show each card as something like this:

From the Velvet palette

Step 6: Add Styling

I chose SASS to style this project. It has a lot of benefits, such as the use of functions, mixins, and a bunch of other cool stuff. It's also a very consolidated style sheet language.

Inside the <style></style> tag, insert the following:

<style lang="scss">
.palette-picker-generator {
  padding: 20px;
  display: flex;
  justify-content: center;
  &__palette-wrapper {
    display: flex;
  }
  &__palette-item {
    cursor: pointer;
    width: 200px;
    height: 200px;
  }
}
</style>

And add this to the template:

<div v-for="(palette, index) in palettes" :key="index">
  <h2 class="mt-5 mb-5 headline font-weight-light">
    {{ palette.name }}
  </h2>
  <div class="palette-picker-generator__palette-wrapper">
    <v-card
      v-for="color in palette.colors"
      :key="color"
      :style="{ backgroundColor: `#${color}` }"
      class="palette-picker-generator__palette-item"
      @click="savePalette(color)"
    >
      <v-card-text>
        {{ color }}
      </v-card-text>
    </v-card>
  </div>
</div>

It should result in the following:

Styled Color Palettes

Step 7: Time for Machine Learning

Currently, we have a static page that will do nothing but show a few pre-defined palettes. But we won't stop there. Let's use the Colormind API to use machine learning for our color palettes. Pretty awesome, huh?

We'll need to make http requests. So we could simply ask for content with a function that uses the fetch API, right? Almost right. The problem with that approach is that it's quite insecure if we choose to host our app using https while trying to make an http request.

To solve that, we need to create a Nuxt serverMiddleware. It will use a connect instance to register additional routes without the need for an external server to handle http/https requests. The middleware is just a function that receives request and response objects, and the next function.

So let's create a file in api/palette-picker.js (in the application root). Write the following:

import 'isomorphic-fetch'

export default async function(req, res, next) {
  const data = await fetch('http://colormind.io/api/', {
    method: 'POST',
    body: JSON.stringify({
      model: 'default'
    })
  })
    .then(result => result.json())
    .catch(console.log)

  res.end(JSON.stringify(data))
}

Note that we have to install isomorphic-fetch, since the fetch API is not available server-side. To install it, type in your terminal:

npm install isomorphic-fetch

or

yarn add isomorphic-fetch

Our function will POST to the Colormind API with the data model that we want to use to get color palettes. It returns an array of RGBs, like this:

{
  "result": [
    [190, 73, 73],
    [182, 144, 75],
    [222, 215, 173],
    [55, 152, 202],
    [33, 136, 116]
  ]
}

In our component, let's write this:

// Below script tag
import fetchColors from '@/utils/palette-picker'

// Inside methods object
methods: {
  //... some code above
  toHex(r, g, b) {
    return [r, g, b]
      .reduce((acc, curr) => {
        let hex = Number(curr).toString(16)
        acc.push(hex.length < 2 ? (hex = '0' + hex) : hex)
        return acc
      }, [])
      .join('')
  },

  async getPalette() {
    const { result } = await fetch('api/palette-picker')
      .then(result => result.json())
      .catch(console.log)

    const colors = result.map(colors => {
      const [r, g, b] = colors
      return this.toHex(r, g, b)
    })
    this.palettes.unshift({
      // here we can use some random name generator,
      // but for the sake of simplicity I'm going
      // to add just the length of array as the name
      name: this.palettes.length,
      colors
    })
  },
  //... some more code below
}

The functions above simply request a new palette, transform the result to a hex value, create a palette, and insert the first item into the array of palettes.

In our template, we write the following:

<v-btn class="mb-5" @click="getPalette">
  Randomize
</v-btn>

Step 8: Pick a Color

Let's now implement a function to copy the color to the clipboard when a user clicks on it. Add a savePalette function to v-card and pass the color to it.

  <v-card
    v-for="color in palette.colors"
    :key="color"
    :style="{ backgroundColor: `#${color}` }"
    class="palette-picker-generator__palette-item"
    @click="savePalette(color)"
  >
    <v-card-text>
      {{ color }}
    </v-card-text>
  </v-card>

Then, in our methods object, add the following:

methods: {
  // some code above
  savePalette(color) {
    navigator.clipboard.writeText(`#${color}`)
  }
  // some code below
}

It will copy the palette value to your clipboard so you can use it in your project.


That's it! You've created your own color palette generator. Of course, you can do a lot more. For more context, you can find the repository with all implementation details and all the code here. It also has some other nice things, such as a Snackbar when a user clicks a color.

Once again, you can find the repository of all my other open-source tools here. More articles about my other tools are soon to follow. Keep your eyes peeled for them by regularly checking out X-Team's blog or by subscribing to the X-Team Weekly newsletter.