Building a Pinterest Clone with Node.js, Express, and MongoDB

Building a Pinterest Clone with Node.js, Express, and MongoDB

Introduction: Welcome to this step-by-step guide where we'll walk through the process of creating a Pinterest clone using Node.js, Express, and MongoDB. We'll be using popular packages such as Express-generator, Passport, Passport-local, Passport-local-mongoose, Mongoose, Express-session, and Multer. Let's get started!

Step 1: Setting Up the Project

Install Express Generator:

npm install -g express-generator

Create a New Express App:

express pinterest-clone --view=ejs
cd pinterest-clone
npm install

Step 2: Installing Passport and Other Dependencies

Install Passport:

npm install passport

Install Passport-local:

npm install passport-local

Install Passport-local-mongoose:

npm install passport-local-mongoose

Install Mongoose:

npm install mongoose

Install Express-Session:

npm install express-session

Step 3: Configuring Express-Session and Passport in App.js

var expressSession = require('express-session');
var passport = require('passport');

app.use(expressSession({
  resave:false,
  saveUninitialized:false,
  secret: 'your-secret-key'
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(usersRouter.serializeUser());
passport.deserializeUser(usersRouter.deserializeUser());

Step 4: Creating User and Post Models

Create models/user.js:

var mongoose = require('mongoose');
var plm = require('passport-local-mongoose');

mongoose.connect("mongodb://127.0.0.1:27017/pnterestServer");

const userschema = mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  fullname: {
    type: String,
    required: true,
  },
  password: {
    type: String,
  },
  posts: [{
    type: mongoose.Schema.Types.ObjectId,
    ref:'Post'
  }],
  dp: {
    type: String,
  }

});

userschema.plugin(plm);
module.exports = mongoose.model('user', userschema);

Create models/post.js:

const mongoose = require('mongoose');

const postSchema = new mongoose.Schema({
    posttext :{
        type: String,
        required: true
    },
    image:{
     type : String,
    },
    user:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'User'
    },
    createdate:{
        type: Date,
        default: Date.now,
    },
    likes:{
        type: Array,
        default: [],
    }
})

module.exports = mongoose.model('Post', postSchema);

Step 5:Creating Index.js.

configuring express, router, passport-local, passport.

Create index.js:

var express = require('express');
var router = express.Router();
var userModel = require('./users');
var postModel = require('./post');
const localStrategy = require('passport-local');
const upload = require('./multer');

const passport = require('passport');
passport.use(new localStrategy(userModel.authenticate()));


router.get('/', function(req, res, next) {
  res.render('index');
});
router.get('/profile', isLoggedin,async function(req, res, next) {
  const user = await userModel.findOne({
   username : req.session.passport.user
  })
  .populate('posts')
  console.log(user);
  res.render('profile',{user});
});
router.get('/login', function(req, res, next) {
res.render('login',{ error: req.flash('error')} );
});
router.get('/feed', function(req, res, next) {
  res.render('feed');
});
router.post('/register', function(req, res) {
  const{username , email , fullname } = req.body;
  const userdata = new userModel({username, email,fullname});

  console.log("done");
  userModel.register(userdata,req.body.password)
  .then(function() {
    passport.authenticate("local")(req, res,function(){
      res.redirect('/profile');
    })
  })
});

router.post('/login',passport.authenticate("local",{
  successRedirect:"/profile",
  failureRedirect:"/login",
  failureFlash:true
}) ,function(res,req){});

router.get('/logout', function(req, res, next){
  req.logout(function(err) {
    if (err) { return next(err); }
    res.redirect('/login');
  });
});

router.post('/upload', isLoggedin,upload.single('file') , async function(req, res, next){
  if(!req.file){
    return res.status(404).send("No files were uploaded")
  }
  const user = await userModel.findOne({username:req.session.passport.user})
  const post = await postModel.create({
    image:req.file.filename,
    posttext:req.body.filecaption,
    user:user._id
  })

  user.posts.push(post._id)
  await user.save()
  res.redirect("/profile");
});

function isLoggedin(req,res,next){
if(req.isAuthenticated()){
  return next();}
  res.redirect('/login');
}


module.exports = router;

Step 6: Creating Registration, Login, Profile, Feed ,Upload and Logout Pages.

Create views/register.ejs:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Register</title>
  <link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
  <div class="container">
    <div class="content">
      <!--pinterest logo-->
      <img src="https://i.pinimg.com/originals/d3/d1/75/d3d175e560ae133f1ed5cd4ec173751a.png" alt="pin logo" class="img1" />
      <p class="header">Register to see more</p>
    <form action="/register" method="post">
      <input name="email" type="email" placeholder="Email" class="detail" /><br />
      <input name="fullname" type="text" placeholder="fullname" class="detail" /><br />
      <input name="username" type="text" placeholder="username" class="detail" /><br />
      <input name="password" type="password" placeholder="Password" class="detail" />
      <input type="submit" class="btn int" value="Register">
    </form>

      <p class="or">OR</p>
      <button class="btn fbk">
        <i
          class="fab fa-facebook fa-lg"
          style="color: white; padding-right: 10px"
        ></i
        ><a href="#">Continue with Facebook</a></button
      ><br />
      <button class="btn ggl">
        <i
          class="fab fa-google"
          style="color: rgb(11, 241, 22); padding-right: 10px"
        ></i
        ><a href="#">Continue with Google</a>
      </button>

      <footer>
        <p>
          By continuing, you agree to Pinterest's
          <b>Terms of Service, Privacy policy.</b>
        </p>
        <hr />

      </footer>
    </div>
  </div>
  <a href="/login" class="upbtn">Log in</a>

</body>
</html>

Create views/login.ejs:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Register</title>
  <link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
  <div class="container">
    <div class="content">
      <!--pinterest logo-->
      <img src="https://i.pinimg.com/originals/d3/d1/75/d3d175e560ae133f1ed5cd4ec173751a.png" alt="pin logo" class="img1" />
      <p class="header">Log in to Your Account</p>
      <% if(error.length > 0){ %>
        <p class="error"> <%= error %> </p>
    <% } %>


    <form action="/login" method="post">
      <input name="username" type="text" placeholder="username" class="detail" /><br />
      <input name="password" type="password" placeholder="Password" class="detail" />
      <input type="submit" class="btn int" value="Login">
    </form>
      <a href="/">Forgot your password?</a>

      <p class="or">OR</p>
      <button class="btn fbk">
        <i
          class="fab fa-facebook fa-lg"
          style="color: white; padding-right: 10px"
        ></i
        ><a href="#">Continue with Facebook</a></button
      ><br />
      <button class="btn ggl">
        <i
          class="fab fa-google"
          style="color: rgb(11, 241, 22); padding-right: 10px"
        ></i
        ><a href="#">Continue with Google</a>
      </button>

      <footer>
        <p>
          By continuing, you agree to Pinterest's
          <b>Terms of Service, Privacy policy.</b>
        </p>
        <hr />
        <p>Not on Pinterest yet?</p> <a href="/">Sign up</a>
      </footer>
    </div>
  </div>
  <a href="/" class="upbtn">Sign up</a>

</body>
</html>

Create stylesheets/style.css:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  background-color: gray;
  font-family: Arial, Helvetica, sans-serif;
}
.container {
  background-color:white;
  width: 480px;
  min-height: 650px;
  position: absolute;
  margin: auto;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-radius: 10px;
  box-shadow: 2px 2px 3px -1px rgba(0, 0, 0, 0.5);
}
.content {
  width: 56%;

  margin: auto;

  text-align: center;
}

.img1{
  width: 70px;
  position: relative;
  top: 20px;
}
.header {
  font-size: 32px;
  font-weight: 700;
  margin-top: 40px;
  margin-bottom: 10px;
  line-height: 34px;
}
.detail {
  width: 100%;
  height: 48px;
  margin: 5px;
  padding: 15px;
  font-size: 15px;
  color: gray;
  border: 2px solid rgb(218, 214, 214);
  border-radius: 15px;
}
.detail:focus {
  box-shadow: 0px -7px 3px -2px rgba(15, 91, 231, 0.4),
    0px 7px 3px -2px rgba(15, 91, 231, 0.4),
    7px 0px 3px -2px rgba(15, 91, 231, 0.4),
    -7px 0px 3px -2px rgba(15, 91, 231, 0.4);
  outline: none;
}

h4 {
  font-size: 13px;
  font-weight: 700;
  position: relative;
  left: -60px;
  margin: 5px;
}

.btn {
  width: 100%;
  height: 40px;
  border: hidden;
  border-radius: 20px;
  font-size: 18px;
  margin: 5px 0px;
}

.int {
  background-color: #f30d19;
  margin: 10px 0px;
  color: white;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
}
.int:hover{
  background-color: #df0812;
}

.or {
  font-size: 15px;
  font-weight: 700;
  margin: 10px 0px;
}

.fbk {
  background-color: rgb(9, 128, 240);
  margin: 5px 0px;
  font-size: 16px;
  font-weight: 700;
}
.fbk a {
  text-decoration: none;
  color: white;
  text-align: center;
  letter-spacing: 1px;
}
.fbk:hover{
  background-color: rgb(8, 110, 206);
}
.ggl{
  text-align: center;
  background-color: #ccc;
}
.ggl a {
  text-decoration: none;
  color: black;
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 1px;
}
.ggl:hover{
  background-color: #a0a0a0;
}

footer p {
  font-size: 12px;
  margin: 10px;
  opacity: 0.7;
}
p:last-child {
  opacity: 1;
}
hr {
  width: 50%;
  opacity: 0.4;
  margin-left: 25%;
}
.upbtn{
  position: relative;
  text-decoration: none;
  color: black;
  top: 50px;
  left: 140px;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  width: 126px;
  padding: 11px 20px;
  background-color: rgb(241, 236, 236);
  border-radius: 20px;
}
.error{
  font-weight: 500;
  color: red;
  margin: 7px 0;
  text-transform: capitalize;
}

Create views/profile.ejs:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Profile</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
        <link rel="stylesheet" href="/stylesheets/profile.css">
</head>
  <body>
    <div class="containerrr">
        <div class="carddd">
          <div class="profile-picture">
            <img src="https://images.unsplash.com/photo-1488161628813-04466f872be2?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fG1vZGVsfGVufDB8fDB8fHww" alt="Profile Picture">
          </div>
          <h2 class="name"><%= user.fullname %></h2>
          <h3 class="username">@<%= user.username %></h3>
          <p class="tagline">bio</p>
          <p class="description">some description</p>
          <a href="/logout" class="button">Log out</a> <hr>
          <form action="/upload" method="post" enctype="multipart/form-data">
            <input class="caption" type="text" name="filecaption" placeholder="Caption">
            <input type="file" name="file" >
            <input class="upload" type="submit" value="Upload">
          </form>
        </div>
    </div>
    <div class="cards flex"> >
        <% user.posts.forEach(function(post){ %>
            <div class="container">
                <div class="card" style="width: 18rem;">
                    <img src="/images/uploads/<%= post.image %> " class="card-img-top" alt="...">
                    <div class="card-body">
                      <h5 class="card-title"> <%= post.posttext %> </h5>

                    </div>
                  </div>
            </div>
        <% }) %> 
    </div>



    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
  </body>
</html>

Create stylesheets/profile.css:

body {
    font-family: Arial, sans-serif;
    background-color: #dadada;
    margin: 0;
    padding: 0;
  }

  .containerrr {
    max-width: 80%;
    margin: 0 auto;
    padding: 20px;
  }
  .flex{
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    align-items: start;
  }
  .carddd {
    background-color: #fff;
    border-radius: 5px;
    padding: 20px;
    text-align: center;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }

  .profile-picture {
    width: 150px;
    height: 150px;
    border-radius: 50%;
    overflow: hidden;
    margin: 0 auto 20px;
  }

  .profile-picture img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .name {
    font-size: 24px;
    margin: 0;
  }

  .username {
    font-size: 18px;
    color: #777;
    margin: 10px 0;
  }

  .tagline,
  .description {
    color: #555;
    margin: 10px 0;
  }

  .button {
    display: inline-block;
    padding: 10px 20px;
    background-color: #f30d19;
    color: #fff;
    text-decoration: none;
    border-radius: 5px;
    transition: background-color 0.3s;
  }

  .button:hover {
    background-color: #d80e18;
  }

  .caption{
    border-radius: 30px;
    border: 1px solid black;
    padding: 7px 11px;
  }
  .upload{
    display: inline-block;
    padding: 10px 20px;
    background-color: #f30d19;
    color: #fff;
    border: none;
    text-decoration: none;
    border-radius: 5px;
    transition: background-color 0.3s;
  }

Create views/logout.ejs:

Create views/feed.ejs:

<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
  <title>Pinteresting | Gallery Layout</title>
  <link rel="stylesheet" href="/stylesheets/feed.css">
</head>
<!-- A Simple non functional Pinterest inspired page layout created using only HTML and CSS.
       Created by M. Hassler - Hassified -->
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>

<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script> -->

<body>
    <div class="container">
        <div class="column">
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/1408221/pexels-photo-1408221.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Pink flowers</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/736230/pexels-photo-736230.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/2350377/pexels-photo-2350377.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>

        </div>
        <div class="column">
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/3601531/pexels-photo-3601531.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Pink flowers</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/772520/pexels-photo-772520.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/3262437/pexels-photo-3262437.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
        </div>
        <div class="column">
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/1697912/pexels-photo-1697912.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Pink flowers</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/1591140/pexels-photo-1591140.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/2057047/pexels-photo-2057047.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
        </div>
        <div class="column">
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/60909/rose-yellow-flower-petals-60909.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/4121204/pexels-photo-4121204.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/4122767/pexels-photo-4122767.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
          <div class="content-wrapper">
            <div class="image-wrapper">
              <div class="overlay">
              <div>
                <p>Creator</p>
                <button class="save">Save</button>
              </div>
              <div>
                <button class="spheric-button">
                  twitter.com
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/3580/3580382.png" alt="">
                </button>
                <button class="round-button">
                  <img src="https://cdn-icons-png.flaticon.com/512/512/512142.png" alt="">
                </button>
              </div>
            </div>
               <img src="https://images.pexels.com/photos/2626152/pexels-photo-2626152.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1" alt="">
            </div>
            <p>Cool image</p>
          </div>
        </div>
      </div>
</body>

</html>

Create stylesheets/feed.css:

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    --red: #e60023;
  }

  body, html  {
    width: 100%;
  }

  body {
    display: grid;
    place-items: center;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Helvetica, "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", メイリオ, Meiryo, "MS Pゴシック", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";;
  }

  .container {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    max-width: 100%;
    column-gap: 1em;
    padding: 2em;
  }

  .image-wrapper {
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
  }

  .image-wrapper > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 16px;
  }

  .column {
    display: flex;
    flex-direction: column;
    gap: 3em;
  }

  .content-wrapper p {
    padding: 0.5em 0 0 0.5em;
    font-weight: bold;
  }

  .overlay {
    cursor: zoom-in;
    position: absolute;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.5);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    border-radius: 16px;
    padding: 0.75em;
    color: white;
    opacity: 0;
  }

  .overlay:hover {
    opacity: 1;
  }

  .overlay div {
    display: flex;
    width: 100%;
    justify-content: space-between;
  }

  .overlay div > p {
    cursor: pointer;
  }

  .overlay div .round-button:nth-child(2) {
    margin-left: auto;
    margin-right: 0.7em;
  }
  .round-button {
    width: 2.4em;
    height: 2.4em;
    border: none;
    border-radius: 50%;
    display: grid;
    place-items: center;
    opacity: 0.8;
  }

  .round-button img {
    width: 60%;
    height: 60%;
  }

  .spheric-button {

    border-radius: 50px;
    border: none;
    padding: 0.5em 01.25em;
    opacity: 0.8;
    font-weight: 800;
  }

  .spheric-button:hover, .round-button:hover {
    opacity: 1;
    cursor: pointer;
  }

  .save {
    padding: 1em 1.5em;
    border: none;
    border-radius: 50px;
    color: white;
    font-weight: 900;
    cursor: pointer;
    background-color: var(--red);
  }

  .save:hover {
    background-color: #ad081b;
  }


  @media (max-width: 1050px) {
    .container {
       grid-template-columns: repeat(3, 1fr);
    }

    .column:last-child {
      display: none;
    }
  }

  @media (max-width: 800px) {
    .container {
       grid-template-columns: repeat(2, 1fr);
    }

    .column:nth-child(3) {
      display: none;
    }
  }

  @media (max-width: 550px) {
    .container {
       grid-template-columns: 1fr;
      gap: 3em;
    }

    .column:nth-child(3) {
      display: flex;
    }

    .column:last-child {
      display: flex;
    }

  }

Step 7: Setting Up Image Uploads with Multer

Install Multer:

npm install uuid multer

Create multer.js:

const multer = require('multer');
const {v4 : uuidv4} = require('uuid');
const path = require('path');
const storage = multer.diskStorage({
    destination : function(req,file ,cb){
        cb(null,'./public/images/uploads')
    },
    filename: function(req,file,cb){
        const uniqueFilename = uuidv4();
        cb(null , uniqueFilename+path.extname(file.originalname));

    }
});

const upload = multer({storage : storage});

module.exports = upload;

index.js

const upload = require('./multer');

router.post('/upload', isLoggedin,upload.single('file') , async function(req, res, next){
  if(!req.file){
    return res.status(404).send("No files were uploaded")
  }
  const user = await userModel.findOne({username:req.session.passport.user})
  const post = aw/ait postModel.create({
    imag/////e:req.file.filename,
    posttext:req.body.filecaption,
    user:user._id
  })

  user.posts.push(post._id)
  await user.save()
  res.redirect("/profile");
});

Thus we have successfully created a Pinterest clone using Node.js, Express, and MongoDB. This is a basic implementation, and you can further enhance it by adding features such as image categorization, user profiles, and more.

Thank You !!