Identification on the world wide web is a critical component that we connect with through various social media platforms. Gravatar, a service meaning Globally Recognized Avatar built by WordPress, provides a universal image that identifies you across the web. This image is proper, especially when you comment on blog sites and interact online.
In this tutorial, we'll discuss how to build a Gravatar service in NextJS. We'll use Cloudinary for media storage, transformation, and delivery.
Sandbox
You can find the source code of the entire project on Codesandbox. Fork it to run the code.
1<CodeSandbox id="long-sunset-hnrpp" title="build a gravatar service in next.js" />
Prerequisites
We focused on building this project with Next.js, a React.js framework. However, experience in JavaScript and React is a necessity. To follow through the steps, we also need to do the following:
- Set up an account on Cloudinary. It is free to signup.
- Have NodeJS and
npm
installed on our computer. We use npm, a package manager, to install dependencies for our program. NPM is available when you installnode
. - Use a code editor of our choice.
Installation
To set up the starter project for development, install the boilerplate on our machine and run the command.
1npx create-next-app nextvatar && cd nextvatar
After the installation of nextvatar
, we need to install the required dependencies.
1npm install cloudinary-react lodash
cloudinary-react
, a Cloudinary plugin we use to transform and render stored images from Cloudinary into our React components. The Cloudinary upload widget requires Lodash.
Cloudinary Widget
To handle image uploads, we’ll utilize the Cloudinary upload widget.
First, we add the Cloudinary widget’s JavaScript file from a CDN to the head
of the page in the sections/Layout.js
. We'll create a folder titled 'sections' and in it a file titled Layout.js with the following content.
<!— Can you please mention to create folder ‘sections’ and new file ‘Layout.js’ —>
sections/Layout.js
1import Head from "next/head";23 const Layout = ({ children, pageMeta }) => {4 return (5 <>6 <Head7 <script8 src="https://upload-widget.cloudinary.com/global/all.js"9 type="text/javascript"10 ></script>11 </Head>12 <div>13 <main>{children}</main>14 </div>15 </>16 );17 };18 export default Layout;
With the widget script installed, we create a widget instance on the home page.
pages/index.js
1import React, { useState } from "react";2 import Layout from "../sections/Layout";3 import styles from "../styles/Home.module.css";45 export default function IndexPage() {6 const [url, setUrl] = useState(null);78 const widget = () => {9 setUrl(null);1011 window.cloudinary12 .createUploadWidget(13 {14 cloudName: "terieyenike",15 uploadPreset: "avatar"16 },17 (error, result) => {18 if (!error && result && result.event === "success") {19 setUrl(result.info.url);20 }21 }22 )23 .open();24 };2526 return (27 <div className={styles.container}>28 <Layout>29 <div className={styles.main}>30 <h1 className={styles.heading}>NEXTVATAR</h1>31 <p className={styles.small}>An enhanced Gravatar</p>32 {/* Rendered JSX goes in here */}33 </div>34 </Layout>35 </div>36 );37 }
Here, we configured the upload widget using our cloud_name and an upload preset in a widget
function. The image URL returned from the upload is assigned to a state variable, url
.
The cloud name is a unique identifier for our Cloudinary account. You can retrieve it from our Cloudinary dashboard. You can find out more about an upload preset here.
Trigger an image upload
With a complete widget setup, we define the JSX markup to render a button that opens the widget. We also defined a text field to display the returned URL after a successful upload.
pages/index.js
1import React from "react";2 {/* other imports go below here */}34 export default function IndexPage() {5 {/* states go here */}67 const widget = () => {8 {/* cloudinary widget code */}9 };10 return (11 <div className={styles.container}>12 <Layout>13 <div className={styles.main}>14 <h1 className={styles.heading}>NEXTVATAR</h1>15 <p className={styles.small}>An enhanced Gravatar</p>16 <button onClick={widget} className={styles.btn}>17 Push a new photo18 </button>19 <p className={styles.pStyle}>20 <span>URL:</span> {url}21 </p>22 </div>23 </Layout>24 </div>25 );26 }
Finally, we can import the following:
- The file
Logo.js
in thecomponents
folder that contains the brand name,Nextvatar
into the componentsections/Header.js
- Also, include the
Footer.js
andHeader.js
files into theLayout.js
file.
<!— can you please mention to create folder ‘components’ and new file ‘Logos.js’ —> We create a new folder called 'components' with the file 'Logo.js' having the following content.
components/Logo.js <!— Fix to BOLD instead of italics —>
1import React from "react";2 import Link from "next/link";3 import styles from "../styles/Home.module.css";4 const Logo = () => {5 return (6 <Link href="/">7 <a className={styles.logo}>8 <span className={styles.logo__name}>Nextvatar</span>9 </a>10 </Link>11 );12 };13 export default Logo;1415**sections/Header.js**16<!— Fix to BOLD instead of italics —>1718 import Logo from "../components/Logo";19 import styles from "../styles/Home.module.css";20 const Header = () => {21 return (22 <header>23 <div className={styles.container}>24 <nav className={styles.nav}>25 <ul className={styles.nav__ul}>26 <Logo />27 </ul>28 </nav>29 </div>30 </header>31 );32 };33 export default Header;
sections/Footer.js <!— Fix to BOLD instead of italics —>
1import styles from "../styles/Home.module.css";2 const Footer = () => {3 return (4 <div>5 <footer className={styles.footer}>6 <address className={styles.container}>7 © {new Date().getFullYear()} | Made with ♥, remote.{" "}8 <span>Built with NextJS and Cloudinary</span>9 </address>10 </footer>11 </div>12 );13 };14 export default Footer;
sections/Layout.js <!— Fix to BOLD instead of italics —>
1import Head from "next/head";2 import Footer from "./Footer";3 import Header from "./Header";4 import { useRouter } from "next/router";5 const Layout = ({ children, pageMeta }) => {6 // component definitions go in here7 return (8 <>9 <Head>10 <script11 src="https://upload-widget.cloudinary.com/global/all.js"12 type="text/javascript"13 >14 </Head>15 <div>16 <Header />17 <main>{children}</main>18 <Footer />19 </div>20 </>21 );22 };23 export default Layout;
<!— Final Layout.js page wonky, when I copied code over from procedure it did not function.. here is the fixed version
— const Layout = ({ children, pageMeta }) => { // component definitions go in here return (
1<div>2 <Head>3 <script4 src="https://upload-widget.cloudinary.com/global/all.js"5 type="text/javascript"6 >7 </script>8 </Head>9 <div>10 <Header />11 <main>{children}</main>12 <Footer />13 </div>14 </div>15 );16};
— COMMENT: WILLIAM - I had shortened the codeblock to remove the lines of code in the 'Head' tag. However, I just put it back. —>
Styling the interface
This project uses CSS modules and regular stylesheets with the naming convention, [name].module.css
.
One advantage of using CSS modules is that it allows us to use CSS class names without worrying about name clashes. It outputs unique class names for our document.
styles/Home.module.css
1@import url("https://fonts.googleapis.com/css?family=Poppins:200,300,400,500,600,700,800,900&display=swap");23 .main {4 font-family: "Poppins", sans-serif;5 display: flex;6 align-items: center;7 justify-content: center;8 min-height: 100vh;9 flex-direction: column;10 }1112 .container {13 max-width: 75rem;14 width: 85%;15 margin: 0 auto;16 }1718 .btn {19 display: block;20 margin-top: 2em;21 border: 0;22 padding: 1em 2em;23 background: rgba(37, 99, 235, 1);24 color: #fff;25 cursor: pointer;26 font-weight: 700;27 }2829 .nav {30 padding: 1.5em 0;31 }3233 .img {34 max-width: 100%;35 }3637 .nav__ul {38 display: flex;39 align-items: center;40 justify-content: space-between;41 width: 100%;42 }4344 .heading {45 font-size: 2rem;46 font-weight: 700;47 margin-bottom: 0.2em;48 }4950 .pStyle {51 margin-top: 2em;52 width: 100%;53 word-wrap: break-word;54 }5556 .pStyle span {57 display: block;58 font-weight: 700;59 }6061 .small {62 font-size: 0.75rem;63 color: #1a1a1a;64 }6566 .logo {67 display: flex;68 align-items: center;69 color: rgba(37, 99, 235, 1);70 margin: 0;71 padding: 0;72 }7374 .logo__name {75 white-space: nowrap;76 font-size: 1.125rem;77 line-height: 1.75rem;78 font-weight: 700;79 letter-spacing: -0.025em;80 }8182 .section {83 padding: 2em 0;84 }8586 .footer {87 width: 100%;88 text-align: center;89 padding-bottom: 1em;90 z-index: 999;91 font-size: 0.75rem;92 }9394 .footer span {95 display: block;96 margin-top: 0.5em;97 }9899 @media screen and (max-width: 768px) {100 .pStyle span {101 font-size: 1rem;102 }103 }
With the above stylesheet created, we can import it wherever we create a new component and use it to style.
One thing to note here is we can update the _app.js
file with some global syles. The styles will apply to all pages and components in our application.
To avoid conflicts, we may only import the stylesheet in the
pages/_app.js
file.
With this, we can manage the image upload portion of our Gravatar service.
Summary
In this post, we managed the image upload portion of a Gravatar service. In part 2, we will describe how to apply modifications to the uploaded image, transforming it into an avatar.
Resources
You may find these useful: