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.
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.
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.
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
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>
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
}
}
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
}
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> </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:
Velvet
palette
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"> </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> </v-card-text> </v-card> </div>
</div>
It should result in the following:
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>
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> </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.