The idea of a blog article banner gives a pictorial representation of its body. This post discusses implementing an article banner generator that allows us to dynamically select an image of our choice, write some text on it, change the background and text color.
We will use Nuxt.js as our frontend technology. Nuxt is an open-source framework that provides frontend developers with the power to build fast and high-performing websites.
For this post, we’ll store the base banner image on Cloudinary and apply multiple transformations to it.
We completed this project in a CodeSandbox. Fork and run it to quickly get started.
Check the source code on GitHub.
To complete this tutorial, we will need the following:
- Node for installing dependencies
- The knowledge of JavaScript and Vue.js
- A Cloudinary account. Sign up for a free account
We need to scaffold a new project using the CLI
, which will ask a series of questions with the following terminal command:
yarn create nuxt-app image-banner
# OR
npm init nuxt-app image-banner
# OR
npx create-nuxt-app image-banner
With the above command, choose the following configuration as shown below:
Project name: accept the default, press Enter
Programming language: JAVASCRIPT
Package manager: Npm
UI framework: Tailwind CSS
Nuxt.js modules: N/A
Linting tools: N/A
Testing framework: None
Rendering mode: Universal (SSR / SSG)
Deployment target: Static (Static/Jamstack hosting)
Development tools: jsconfig.json
What is your GitHub username? <github-username>
Version control system: GIT
Once the installation is complete, navigate to that directory and start up a development server to preview the app on http://localhost:3000
.
cd image-banner && yarn dev
# or
cd image-banner && npm run dev
Next, we install Cloudinary’s Nuxt.js module with:
yarn add @nuxtjs/cloudinary
# or
npm install @nuxtjs/cloudinary
With the dependency installed, we must add the module in the nuxt.config.js
file under the modules section.
nuxt.config.js
modules: [
"@nuxtjs/cloudinary"
]
Below the modules section, add the following to configure Cloudinary with the useComponent
and cloudName
field option.
nuxt.config.js
modules: [
"@nuxtjs/cloudinary"
],
// add this
cloudinary: {
cloudName: "<your-cloud-name>",
useComponent: true,
}
useComponent
set to true allows the use of Vue image components.
You can obtain your Cloudinary cloud name from your dashboard on Cloudinary.
With our app setup completed, we’ll upload two sample royalty-free images to Cloudinary.
In our dashboard, we will have access to upload and save the downloaded images in Cloudinary by clicking the Media Library
tab and Upload
button as displayed in the image below.
Next, we need to copy the publicId for the saved images from our dashboard, which will be necessary to generate the article banner.
In our Nuxt.js project root directory, create a folder called utils
, and within this folder, create a file, banners.json
, with the following json data.
utils/banners.json
[
{
"id": 1,
"publicId": "pexels-christina-morillo-1181681_itscxa",
"alt": "woman on her laptop"
},
{
"id": 2,
"publicId": "pexels-hasan-albari-1229861_njoool",
"alt": "workstation"
}
]
In creating the article banner, we need to set up the markup, styling, and data properties in the script
section of the file, index.vue.
To do this, replace the index.vue
file with the code from this gist, and we’ll explain what is happening after:
https://gist.github.com/Terieyenike/ad9881d156af027eb3c1a7cec2925551
https://gist.github.com/Terieyenike/ad9881d156af027eb3c1a7cec2925551
From the code snippet in the gist, we:
- We created the data method and declared a list of variables to use in the
index.vue
component. This includes the imported image JSON data, image id, the form data, and ashowBanner
boolean field. - We wrote markup to conditionally render the image collection with the
v-if
andv-for
directives. We also bound the class on the image element to dynamically set a border. - Within the markup, we use Cloudinary image components to display the image with the help of the package
@nuxtjs/cloudinary
- We managed a form error message when no image is selected.
- Finally, we set an alternative message using the
v-else
directive in the absence of an image list.
With the above process done, we should have our app looking like this:
We’ll create a Banner
component that establishes a banner image when clicking the Generate Banner button. Create and add the following snippet to components/Banner.vue
.
components/Banner.vue
<template>
<div class="mt-8">
<cld-image :public-id="publicId">
<cld-transformation
:background="bgColour"
crop="fit"
opacity="20"
width="2000"
/>
<cld-transformation
:color="textColour"
:overlay="{
fontFamily: 'Arial',
fontSize: 80,
fontWeight: 'bold',
text: message.toUpperCase(),
}"
/>
<cld-transformation flags="layer_apply"/>
</cld-image>
</div>
</template>
<script>
export default {
props: ["message", "publicId", "bgColour", "textColour"],
};
</script>
The above snippet renders the generated image using the cld-image
and cld-transformation
components, with the message, publicId
, bgColour
, and textColour
as props.
Cloudinary components provide a good experience with setting multiple transformations on an image. These include font properties, block lettering the message property with the method toUpperCase
, opacity, background, and text color attributes.
In the index.vue
file, we import and conditionally render the created Banner
component.
pages/index.vue
<template>
<div class="lg:flex lg:items-center px-8 py-8 max-w-md m-auto md:max-w-2xl lg:m-0 lg-p-0 w-full lg:max-w-5xl">
<div class="lg:w-2/4">
<h1 class="text-gray-900 text-lg mb-2 font-bold uppercase md:text-3xl lg:text-2xl">
<!-- Header title detail here -->
</h1>
<form @submit.prevent="handleSubmit"> <!-- add handleSubmit method -->
<!-- form content details here -->
</form>
</div>
<!-- conditionally render the Banner component here -->
<div v-if="showBanner" class="mt-10 lg:w-2/4 lg:mt-0">
<Banner
:bgColour="formData.backgroundColour"
:message="formData.message"
:publicId="formData.publicId"
:textColour="formData.textColour"
/>
</div>
</div>
</template>
<script>
// import here
export default {
data() {
return {
// data objects code here
}
},
methods: {
// other methods go in here
// add this
handleSubmit() {
if (this.imageId) {
this.showBanner = true
} else {
this.formData.error = true
}
},
},
}
</script>
The above snippet conditionally renders the banner component with the required props. The function handleSubmit
checks if an image is selected before rendering it or throwing an error in its absence.
Our app should look like the image below.
We will quickly add a function to copy the link of the generated image.
In the Banner.vue, we update the source code with the following:
components/Banner.vue
<template>
<div class="mt-8">
<cld-image ref="ref" :public-id="publicId">
<!-- Transformation component goes here -->
</cld-image>
// add this: copiable link section
<div class="mt-10">
<h2 class="mb-2 text-gray-500 font-semibold">Copiable link</h2>
<input
:value="url"
class="w-full border-gray-300 rounded-sm border p-2"
/>
</div>
</div>
</template>
<script>
export default {
props: // props,
// add data objet here
data() {
return {
url: "",
};
},
mounted() {
this.$nextTick(() => {
this.url = this.$refs.ref.$el.src
});
},
};
</script>
The code above does the following:
- Included an empty initialized
url
in the data object - On the
cld-image
component, added theref
attribute to access thesrc
of the underlying image element - The
mounted
lifecycle method, retrieves the image URL and updates theurl
data in the state. - Bound the
url
data to the value of the input element.
The app then looks like this.
Check out the copiable link from the above image.
This post explains how to create a banner image generator using Nuxt.js, with Cloudinary providing media storage and transformations.