DEV Community

Cover image for Blog Dapp(DEV.to Clone) using Nextjs + Tailwindcss + Ether.js + Hardhat + Solidity(Smart Contract) Part-2
Harsh Bardhan
Harsh Bardhan

Posted on

Blog Dapp(DEV.to Clone) using Nextjs + Tailwindcss + Ether.js + Hardhat + Solidity(Smart Contract) Part-2

Now as continuing from part 2 ....

Live Demo Link Of Dapp

Github Repo Link

First we will create the context so that we can interact our ui with blockchain and installing the required packages.

cd blogDapp
mkdir context
yarn add ethers react-nice-avatar timeago-react react-icons

Enter fullscreen mode Exit fullscreen mode

Now create a new file named config.js in root folder...And add the contract address which was deployed and the contract ABI from the artifacts folder in backend folder..

export const contractAddress = "Add your Address";
export const contractABI = ["Add_The_Abi"]
Enter fullscreen mode Exit fullscreen mode

Next create a file insite context folder named context.js

import { createContext, useEffect, useState } from "react";
import { ethers } from "ethers";
import { contractABI, contractAddress } from "../config";
import { useRouter } from "next/router";

export const appContext = createContext();

export const AppProvider = ({ children }) => {
  const [account, setAccount] = useState("");
  const [loading, setLoading] = useState(false);
  const [balance, setBalance] = useState(0);
  const [posts, setPosts] = useState([]);
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");
  const [tag, setTag] = useState("");
  const [currentPost, setCurrentPost] = useState([]);
  const [commentContent, setCommentContent] = useState("");
  const [comments, setComments] = useState([]);

  const checkIfWalletIsConnected = async () => {
    try {
      if (!ethereum) {
        console.log("Make sure you have metamask!");
        return;
      }
      const accounts = await ethereum.request({ method: "eth_accounts" });
      if (accounts.length !== 0) {
        const account = accounts[0];
        setAccount(account);
      } else {
        console.log("No authorized account found");
        setAccount(null);
      }

      const provider = new ethers.providers.Web3Provider(ethereum);

      const amount = await provider.getBalance(account);
      setBalance(ethers.utils.formatEther(amount));

      ethereum.on("accountsChanged", (accounts) => {
        if (accounts.length !== 0) {
          const account = accounts[0];
          setAccount(account);
        } else {
          console.log("No authorized account found");
          setAccount(null);
        }
      });
    } catch (error) {}
  };

  const connectWallet = async () => {
    try {
      if (!ethereum) {
        alert("Get MetaMask!");
        return;
      }
      const accounts = await ethereum.request({
        method: "eth_requestAccounts",
      });
      console.log("Connected", accounts[0]);
      setAccount(accounts[0]);
    } catch (error) {
      console.log(error);
    }
  };

  const createPosts = async () => {
    try {
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(
        contractAddress,
        contractABI,
        signer
      );

      const transaction = await contract.createPost(title, content, tag);
      setLoading(true);
      await transaction.wait();
      setLoading(false);
    } catch (error) {
      console.log(error);
    }
  };

  const getPosts = async () => {
    try {
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(
        contractAddress,
        contractABI,
        signer
      );
      const get = await contract.getPosts();
      setPosts(get);
    } catch (error) {
      console.log(error);
    }
  };

  const router = useRouter();
  const likePost = async (id) => {
    try {
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(
        contractAddress,
        contractABI,
        signer
      );
      const transaction = await contract.LikePost(id);
      setLoading(true);
      await transaction.wait();
      setLoading(false);
      router.push("/");
    } catch (error) {
      console.log(error);
    }
  };

  const showPost = async (id) => {
    try {
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(
        contractAddress,
        contractABI,
        signer
      );
      const get = await contract.getPost(id);
      setCurrentPost(get);
    } catch (error) {}
  };

  const writeComments = async (id) => {
    try {
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(
        contractAddress,
        contractABI,
        signer
      );

      const tnx = await contract.writeComment(id, commentContent);
      setLoading(true);
      await tnx.wait();
      setLoading(false);
    } catch (error) {
      console.log(error);
    }
  };

  const readComments = async (id) => {
    try {
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(
        contractAddress,
        contractABI,
        signer
      );

      const read = await contract.getPostComments(id);
      setComments(read);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    checkIfWalletIsConnected();
    getPosts();
  });

  return (
    <appContext.Provider
      value={{
        connectWallet,
        account,
        balance,
        createPosts,
        setContent,
        setTitle,
        setTag,
        posts,
        likePost,
        showPost,
        currentPost,
        loading,

        readComments,
        writeComments,
        setCommentContent,
        comments,
      }}
    >
      {children}
    </appContext.Provider>
  );
};


Enter fullscreen mode Exit fullscreen mode

Create the folder components in the root folder and then follow along:

Now adding the below codes to the required files

components/Navbar.js

import React, { useContext } from "react";
import { appContext } from "../context/context";
import { FaEthereum } from "react-icons/fa";
import { BiSearchAlt2 } from "react-icons/bi";
import { FaConnectdevelop } from "react-icons/fa";
import { useRouter } from "next/router";

const Navbar = () => {
  const router = useRouter();
  const { connectWallet, account, balance } = useContext(appContext);
  return (
    <header className={styles.wrapper}>
      <div className={styles.container}>
        <div className={styles.left}>
          <div className={styles.logo} onClick={() => router.push("/")}>
            DEV
          </div>
          <div className={styles.mid}>
            <input
              type="text"
              placeholder="Search"
              className={styles.input}
              autoComplete="off"
              autoCorrect="off"
              spellCheck="false"
            />
            <BiSearchAlt2 className="hidden md:inline-flex h-6 w-6" />
          </div>
        </div>
        <div className={styles.right}>
          <div className={styles.rightInner}>{balance} ETH</div>
          <div>
            {account ? (
              <div className={styles.rightInner}>
                <div>
                  <FaEthereum />
                </div>
                <div>
                  {account.slice(0, 8)}...{account.slice(-8, account.length)}
                </div>
              </div>
            ) : (
              <div className={styles.rightInner} onClick={connectWallet}>
                <FaConnectdevelop />
                <div>Connect Wallet</div>
              </div>
            )}
          </div>
        </div>
      </div>
    </header>
  );
};

export default Navbar;

const styles = {
  wrapper: `bg-white shadow-md h-16 items-center py-2 sticky top-0 z-50`,
  container: `flex items-center justify-between max-w-7xl mx-auto`,
  left: `ml-3 flex space-x-3`,
  rightInner: `bg-gray-100 p-2 rounded-md flex space-x-3 items-center cursor-pointer font-semibold`,
  right: `flex items-center space-x-3 mr-3 hidden md:inline-flex`,
  logo: `p-2 bg-black text-white font-bold text-lg rounded-md cursor-pointer`,
  input: `bg-transparent ml-2 p-2 rounded-md `,
  mid: `flex items-center space-x-3 bg-gray-100 px-2 rounded-md hidden md:inline-flex`,
};

Enter fullscreen mode Exit fullscreen mode

components/Sidebar.js

import React from "react";
import { RiHomeHeartFill } from "react-icons/ri";
import { BiSearchAlt2 } from "react-icons/bi";
import { IoIosNotificationsOutline } from "react-icons/io";
import { BiMessageSquareDetail } from "react-icons/bi";
import { BsBookmarkStar } from "react-icons/bs";
import { IoListSharp } from "react-icons/io5";
import { BsPerson } from "react-icons/bs";
import { CgMoreO } from "react-icons/cg";
import { BsGithub } from "react-icons/bs";
import { BsTwitter } from "react-icons/bs";
import { BsLinkedin } from "react-icons/bs";

const Sidebar = () => {
  return (
    <div className={styles.wrapper}>
      <div className={styles.container}>
        <div className={`${styles.icon} text-green-500 font-extrabold`}>
          <RiHomeHeartFill />
          <div className={styles.name}>Home</div>
        </div>

        <div className={styles.icon}>
          <BiSearchAlt2 />
          <div className={styles.name}>Explore</div>
        </div>

        <div className={styles.icon}>
          <IoIosNotificationsOutline />
          <div className={styles.name}>Notifications</div>
        </div>

        <div className={styles.icon}>
          <BiMessageSquareDetail />
          <div className={styles.name}>Messages</div>
        </div>

        <div className={styles.icon}>
          <BsBookmarkStar />
          <div className={styles.name}>Bookmarks</div>
        </div>

        <div className={styles.icon}>
          <IoListSharp />
          <div className={styles.name}>Lists</div>
        </div>

        <div className={styles.icon}>
          <BsPerson />
          <div className={styles.name}>Profile</div>
        </div>

        <div className={styles.icon}>
          <CgMoreO />
          <div className={styles.name}>More</div>
        </div>
      </div>
      <div className={styles.lower}>
        <div className={styles.icon}>
          <BsGithub />
        </div>
        <div className={styles.icon}>
          <BsTwitter />
        </div>
        <div className={styles.icon}>
          <BsLinkedin />
        </div>
      </div>
    </div>
  );
};

export default Sidebar;

const styles = {
  wrapper: `mt-5`,
  container: `flex flex-col gap-7 `,
  icon: `text-2xl text-gray-700 h-6 space-x-2 flex items-center font-semibold hover:scale-110 hover:text-green-500 transition-all duration-300 cursor-pointer ease-in-out`,
  name: `text-xl font-bold text-gray-700 hidden md:inline-flex`,
  lower: `flex flex-row gap-7 mt-[330px] items-center hidden md:inline-flex`,
};

Enter fullscreen mode Exit fullscreen mode

components/Survey.js

import React from "react";
import Image from "next/image";
import survey from "../public/survey.png";

const Survey = () => {
  const Listing = [
    {
      name: "Listings",
      seeAll: true,
      data: [
        {
          title: "Sidekick Live Debugger is now Open Source",
          description: "Product",
        },
        {
          title: "Shakti Packers and Movers Chandigarh",
          description: "Collab",
        },
        {
          title: "Free Laravel & Tailwind CSS Dashboard Template",
          description: "Forsale",
        },
        {
          title:
            "The Tailwind Site Creator, Design Tool, & Component Library 🎨",
          description: "events",
        },
        {
          title:
            "Front-end Foxes Day 2022 - Free Virtual Conference - September 13",
          description: "Product",
        },
      ],
    },
    {
      name: "#discuss",
      seeAll: false,
      data: [
        {
          title: "Sidekick Live Debugger is now Open Source",
          description: "Product",
        },
        {
          title: "Shakti Packers and Movers Chandigarh",
          description: "Collab",
        },
        {
          title: "Free Laravel & Tailwind CSS Dashboard Template",
          description: "Forsale",
        },
        {
          title:
            "The Tailwind Site Creator, Design Tool, & Component Library 🎨",
          description: "events",
        },
        {
          title:
            "Front-end Foxes Day 2022 - Free Virtual Conference - September 13",
          description: "Product",
        },
      ],
    },
    {
      name: "#Product",
      seeAll: false,
      data: [
        {
          title: "Sidekick Live Debugger is now Open Source",
          description: "Product",
        },
        {
          title: "Shakti Packers and Movers Chandigarh",
          description: "Collab",
        },
        {
          title: "Free Laravel & Tailwind CSS Dashboard Template",
          description: "Forsale",
        },
        {
          title:
            "The Tailwind Site Creator, Design Tool, & Component Library 🎨",
          description: "events",
        },
        {
          title:
            "Front-end Foxes Day 2022 - Free Virtual Conference - September 13",
          description: "Product",
        },
      ],
    },
  ];

  return (
    <div className={styles.wrapper}>
      <div className={styles.parts}>
        <Image src={survey} alt="image" height={600} width={800} />
        <div>
          <div className="text-xl font-bold">
            Tell us your thoughts about DEV!
          </div>
          <p className="text-blue-500 font-semibold text-lg mt-2">
            Take the DEV Satisfaction Survey
          </p>
        </div>
      </div>
      <div>
        <div className="flex flex-col gap-5">
          {Listing.map((item, index) => {
            return (
              <div className={styles.parts} key={index}>
                <div className="flex justify-between w-full items-center ">
                  <div className="font-bold text-xl">{item.name}</div>
                  {item.seeAll && (
                    <div className="text-xl font-bold text-blue-500">
                      See All
                    </div>
                  )}
                </div>
                <section className="">
                  {item?.data?.map((data, index) => {
                    return (
                      <div
                        className="border-t-2 flex flex-col space-y-3 py-2"
                        key={index}
                      >
                        <div className="text-lg font-bold">{data.title}</div>
                        <div className="text-sm text-gray-500 pb-2">
                          {data.description}
                        </div>
                      </div>
                    );
                  })}
                </section>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
};

export default Survey;

const styles = {
  wrapper: `hidden lg:inline-flex flex flex-col my-3 max-w-[360px] gap-4 overflow-y-scroll h-[870px] `,
  parts: `border border-gray-300 rounded-md py-6 px-4 bg-white flex flex-col space-y-4`,
};

Enter fullscreen mode Exit fullscreen mode

components/Create.js

import { useRouter } from "next/router";
import React, { useContext } from "react";
import { appContext } from "../context/context";

const create = () => {
  const router = useRouter();
  const { createPosts, setContent, setTitle, setTag, loading } =
    useContext(appContext);

  return (
    <div className="w-full mx-36 flex flex-col gap-8">
      <div className="flex items-center justify-between w-full">
        <div
          className="font-bold text-xl ml-10 border-b-2 border-blue-500"
          onClick={() => router.push("/")}
        >
          All Posts
        </div>
        <button
          onClick={() => router.push("/createPost")}
          className="text-xl font-semibold px-4 py-2 rounded-xl bg-white cursor-default hover:text-orange-500 hover:scale-95 ease-in-out duration-300 transition-all hidden lg:inline-flex"
        >
          Create Post
        </button>
      </div>
      <div>
        <div className="text-2xl font-bold text-blue-500 py-3">Title</div>
        <input
          className="rounded-md px-5 py-2 text-xl"
          placeholder="Title"
          onChange={(e) => setTitle(e.target.value)}
        />
        <div className="text-2xl font-bold text-blue-500 py-3">Tag</div>
        <input
          className="rounded-md px-5 py-2 text-xl"
          placeholder="Tags"
          onChange={(e) => setTag(e.target.value)}
        />
        <div className="text-2xl font-bold text-blue-500 py-3">Content</div>
        <textarea
          className="w-full h-full rounded-md px-5 py-2 text-xl"
          placeholder="Start Typing...."
          onChange={(e) => setContent(e.target.value)}
        />
      </div>

      {loading ? (
        <div className="mt-[250px] w-1/4 text-xl font-bold px-4 py-2 rounded-xl bg-white cursor-default hover:text-orange-500 hover:scale-95 ease-in-out duration-300 transition-all">
          Loading...
        </div>
      ) : (
        <button
          onClick={createPosts}
          className="mt-[250px] w-1/4 text-xl font-bold px-4 py-2 rounded-xl bg-white cursor-default hover:text-orange-500 hover:scale-95 ease-in-out duration-300 transition-all"
        >
          Post
        </button>
      )}
    </div>
  );
};

export default create;

Enter fullscreen mode Exit fullscreen mode

components/Posts.js

import { useRouter } from "next/router";
import React, { useContext } from "react";
import { appContext } from "../context/context";
import Avatar, { genConfig } from "react-nice-avatar";
import TimeAgo from "timeago-react";

const Posts = () => {
  const router = useRouter();
  const { posts, likePost } = useContext(appContext);
  const config = genConfig("hi@dapi.to");

  const formatDate = (timestamp) => {
    let date = new Date(timestamp * 1000);
    let month = date.getMonth() + 1;
    let dt = date.getDate();
    let year = date.getFullYear();
    let seconds = "0" + date.getSeconds();
    let hours = date.getHours();
    let minutes = "0" + date.getMinutes();

    return (
      year +
      "-" +
      month +
      "-" +
      dt +
      " " +
      hours +
      ":" +
      minutes +
      ":" +
      seconds
    );
  };

  return (
    <div className="w-full md:ml-16 ml-5 mr-2 mb-8 md:mr-4 overflow-y-scroll max-h-[780px] md:max-h-[870px] ">
      <div className="flex items-center justify-between w-full">
        <div
          className="font-bold text-xl ml-10 border-b-2 cursor-pointer border-blue-500 hidden md:inline-flex"
          onClick={() => router.push("/")}
        >
          All Posts
        </div>
        <button
          onClick={() => router.push("/createPost")}
          className="text-xl mr-5 font-semibold px-4 py-2 cursor-pointer rounded-xl bg-white hover:text-orange-500 hover:scale-95 ease-in-out duration-300 transition-all"
        >
          Create Post
        </button>
      </div>
      <div className="my-5 space-y-4">
        {posts.map((post) => (
          <div
            key={post.id}
            className="flex flex-col gap-5 bg-white rounded-md px-4 py-5 cursor-pointer"
            onClick={() =>
              router.push({
                pathname: "/showPost",
                query: { id: `${post.id}` },
              })
            }
          >
            <div className="flex space-x-4 items-center text-lg font-normal md:flex-row flex-col">
              <Avatar
                className="w-16 h-16 border-2 border-emerald-500"
                {...config}
              />
              <div className="flex items-center justify-between w-full">
                <div className="flex space-x-5 mt-5">
                  <div className="font-medium">
                    {post.author.slice(0, 8)}....
                    {post.author.slice(-8, post.author.length)}
                  </div>
                  <div className="text-blue-500 font-semibold hidden md:inline-flex">
                    {/* {formatDate(post.timestamp.toNumber())} */}
                    <TimeAgo
                      datetime={formatDate(post.timestamp.toNumber())}
                      locale="vi"
                    />
                  </div>
                </div>

                <button
                  className="cursor-pointer items-center mt-5 "
                  onClick={() => likePost(post.id)}
                >
                  <div>&#10084; {post.likeCount.toNumber()}</div>
                </button>
              </div>
            </div>
            <div className="text-md font-semibold ml-5 ">#{post.tag}</div>

            <div className="mx-4 font-bold text-3xl">{post.title}</div>

            <div className="mx-4 font-lg text-lg">
              {post.content.length > 18 ? (
                <div>{post.content.slice(0, 18)}......</div>
              ) : (
                <div>{post.content}</div>
              )}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Posts;

Enter fullscreen mode Exit fullscreen mode

Now creating the below files in pages folder:

pages/index.js

import React, { useContext } from "react";
import { appContext } from "../context/context";
import Navbar from "../components/Navbar";
import Sidebar from "../components/Sidebar";
import Posts from "../components/Posts";
import Survey from "../components/Survey";

const index = () => {
  const {} = useContext(appContext);
  return (
    <div className={styles.wrapper}>
      <Navbar />
      <div className={styles.container}>
        <div className={styles.main}>
          <Sidebar />
          <Posts />
          <Survey />
        </div>
      </div>
    </div>
  );
};

export default index;

const styles = {
  wrapper: `w-full h-screen bg-gray-100 overflow-hidden`,
  container: `max-w-7xl mx-auto`,
  main: `flex justify-between mx-3 my-2`,
};

Enter fullscreen mode Exit fullscreen mode

pages/createPost.js

import React, { useContext } from "react";
import { appContext } from "../context/context";
import Navbar from "../components/Navbar";
import Sidebar from "../components/Sidebar";
import Create from "../components/Create";

const createPost = () => {
  const {} = useContext(appContext);
  return (
    <div className={styles.wrapper}>
      <Navbar />
      <div className={styles.container}>
        <div className={styles.main}>
          <Sidebar />
          <Create />
        </div>
      </div>
    </div>
  );
};

export default createPost;

const styles = {
  wrapper: `w-full h-screen bg-gray-100 overflow-hidden `,
  container: `max-w-7xl mx-auto`,
  main: `flex justify-between mx-3 my-2`,
};

Enter fullscreen mode Exit fullscreen mode

pages/showPost.js

import { useRouter } from "next/router";
import React, { useContext, useState, useEffect } from "react";
import { appContext } from "../context/context";
import Navbar from "../components/Navbar";
import Sidebar from "../components/Sidebar";
import Avatar, { genConfig } from "react-nice-avatar";
import TimeAgo from "timeago-react";

const showPost = () => {
  const router = useRouter();
  const {
    posts,
    likePost,
    showPost,
    currentPost,
    readComments,
    writeComments,
    setCommentContent,
    comments,
  } = useContext(appContext);
  const { id } = router.query;
  const config = genConfig("hi@dapi.to");

  const gettingPost = async (id) => {
    showPost(id);
  };

  const gettingComments = async (id) => {
    readComments(id);
  };

  const formatDate = (timestamp) => {
    let date = new Date(timestamp * 1000);
    let month = date.getMonth() + 1;
    let dt = date.getDate();
    let year = date.getFullYear();
    let seconds = "0" + date.getSeconds();
    let hours = date.getHours();
    let minutes = "0" + date.getMinutes();

    return (
      year +
      "-" +
      month +
      "-" +
      dt +
      " " +
      hours +
      ":" +
      minutes +
      ":" +
      seconds
    );
  };

  useEffect(() => {
    gettingPost(id);
    gettingComments(id);
  });
  return (
    <div className={styles.wrapper}>
      <Navbar />
      <div className={styles.container}>
        <div className={styles.main}>
          <Sidebar />
          <div className=" w-9/12 mx-2 pb-40 md:mx-5 my-8 space-y-5 overflow-y-scroll max-h-[840px]">
            <div className="flex gap-3 items-center flex-col md:flex-row md:gap-8">
              <Avatar
                className="w-16 h-16 border-2 border-emerald-500"
                {...config}
              />
              <div className="font-semibold text-md">
                Author:{" "}
                {/* {currentPost.author.slice(0, 8)}....
                {currentPost.author.slice(-8, currentPost.author.length)} */}
                {currentPost.author}
              </div>
              <div className="font-semibold text-md text-emerald-500">
                {/* {formatDate(currentPost.timestamp)} */}
                <TimeAgo
                  datetime={formatDate(currentPost.timestamp)}
                  locale="vi"
                />
              </div>
            </div>
            <div className="text-lg text-orange-800 ml-4">
              #{currentPost.tag}
            </div>
            <div className="text-3xl font-extrabold my-5">
              {currentPost.title}
            </div>

            <div className="text-md">{currentPost.content}</div>

            <div>
              {/* comments */}

              <div className="mt-10 border-t-2 pt-10 mr-3 ">
                <div className="flex space-x-4 items-center flex-col md:flex-row gap-8 md:gap-5">
                  <div className="text-lg font-semibold">Write Comments :</div>
                  <div className="flex space-x-5">
                    <input
                      className="rounded-md px-5 py-2 text-xl w-1/2 md:w-full"
                      placeholder="Add Comment...."
                      onChange={(e) => setCommentContent(e.target.value)}
                    />
                    <button
                      className="text-xl font-bold px-4 py-2 rounded-xl bg-white cursor-default hover:text-orange-500 hover:scale-95 ease-in-out duration-300 transition-all"
                      onClick={() => writeComments(currentPost.id)}
                    >
                      Submit
                    </button>
                  </div>
                </div>
                <div className="mt-8">
                  {comments.map((comment, index) => (
                    <div className="border-b-2 py-8" key={index}>
                      <div>
                        <div className="flex items-center space-x-5 flex-col md:flex-row space-y-3 ">
                          <Avatar
                            className="w-8 h-8 border-2 border-emerald-500"
                            {...config}
                          />
                          <div className="items-center flex font-semibold pb-3">
                            {comment.commentor.slice(0, 8)}...
                            {comment.commentor.slice(
                              -8,
                              comment.commentor.length
                            )}
                          </div>
                          <div className="pb-3 hidden md:inline-flex text-green-500 font-medium">
                            <TimeAgo
                              datetime={formatDate(comment.time)}
                              locale="vi"
                            />
                          </div>
                        </div>
                        <div className="text-md mx-4 my-4">{comment.main}</div>
                      </div>
                    </div>
                  ))}
                </div>
              </div>

              {/* end comments */}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default showPost;

const styles = {
  wrapper: `w-full h-screen bg-gray-100 overflow-hidden `,
  container: `max-w-7xl mx-auto `,
  main: `flex justify-between mx-3 my-2`,
};

Enter fullscreen mode Exit fullscreen mode

Now Finally run your app

yarn run dev
Enter fullscreen mode Exit fullscreen mode

Thank you for following up throughout the tutorial...Hope you like the explanation....

Top comments (0)