NextJs - Sidebar

 In the previous tutorial, you learnt to create and run nextjs-app app. In this tutorial, you will be able to add sidebar menu to the app, use bootstrap to style the app., and use icons from react-icons library.

In real project, sidebar menu is an important component. You see most of the websites have sidebar menu. It allows visitors to navigate easily in the applications. Before adding sidebar menu to the app, you have to add bootstrap and react-icons libraries to the app by executing the command below from nextjs-app folder (root folder of the app created in the previous tutorial).

npm install bootstrap react-icons

In the nextjs-app folder, create components folder. In the components folder, create sidebar folder. In the sidebar folder, create three files: SideBar.js, SideBarData.js, and SubMenu.js,

SideBar.js

import React, {useState } from "react";
import Link from 'next/link';
import {FaBars} from "react-icons/fa";
import {AiOutlineClose} from "react-icons/ai";
import { SideBarData } from "./SideBarData";
import SubMenu from "./SubMenu";
import { IconContext } from "react-icons/lib";
import { FaSignInAlt,FaSignOutAlt } from "react-icons/fa"


const nav_style = {
    background: "#0d6efd",
    height: "80px",
    display: "flex",
    justifyCcontent: "flex-start",
    alignItems: "center"
};

const navitem_style = {
    color:"#ffffff",
    marginLeft: "auto", 
    marginRight: "20px"
};
  

const navicon_style = {
  marginLeft: "0.5rem",
  fontSize: "1.8rem",
  height: "70px",
  display: "flex",
  justifyContent: "flex-start",
  alignItems: "center",
  cursor: "pointer",
};
  

const sidebarwrap_style = {
    width: "100%",
};

  
const Sidebar = (props) => {
  const [sidebaropen, setSidebarOpen] = useState(false);
  const showSidebar = () => setSidebarOpen(!sidebaropen);
  const {token} = props;

  const sidebarnav_style = {
    background: "#0d6efd",
    width: "250px",
    height: "100vh",
    display: "flex",
    justifyContent: "center",
    position: "fixed",
    top: 0,
    left: (sidebaropen ? "0" : "-100%"),
    transition: "350ms",
    zIndex: 10,

};

  function isLoggedIn () {
    if(token!==null && token!==''){
      return true;
    }
    else{
      return false;
    }
  }
  const logged=isLoggedIn();

  const links = [
      {
      id: 2,
      path: logged? "/user/logout":"/user/login",
      text: logged?"Logout":"Login",
      icon: logged?<FaSignInAlt/> : <FaSignOutAlt/>
    },

  ]; 

  return (
    <>
      <IconContext.Provider value={{ color: "#fff" }}>
        <div style={nav_style}>
          <div to="#" style={navicon_style}>
            <FaBars onClick={showSidebar} />
          </div>

          <h3
            style={{ textAlign: "center", 
                     marginLeft: "50px", 
                     color: "white" }}
          >
            Admin

          </h3>
          <div style={navitem_style}>
          <ul className="navbar-nav mr-auto list-group-horizontal">
             {links.map(link => {
              return (
                <li key={link.id} className="nav-item">
                  <Link href={{pathname: link.path}}>
                  <a  className="nav-link">{link.icon}{link.text}</a>
                  </Link> 
                </li>
              )
            })}
          </ul> 
          </div>
        </div>
        <div className="nav" style={sidebarnav_style}>
          <div style={sidebarwrap_style}>
            <div to="#" style={navicon_style}>
              <AiOutlineClose onClick={showSidebar} />
            </div>
            {SideBarData.map((item, index) => {
              return <SubMenu item={item} key={index} />;
            })}
          </div>
        </div>
      </IconContext.Provider>
    </>
  );
};
  
export default Sidebar;

The token parameter gotten from another component is used to check whether the user is authenticated. 

SideBarData.js
import React from "react";
import {FaPhone,FaEnvelopeOpenText,FaProductHunt,FaServicestack} from "react-icons/fa";
import {AiFillHome} from "react-icons/ai";
import {IoIosPaper,IoMdHelpCircle} from "react-icons/io";
import {RiArrowUpSFill,RiArrowDownSFill} from "react-icons/ri";
  
export const SideBarData = [
   
    {
    title: "Users",
    path: "",
    icon: <FaServicestack />,
    iconClosed: <RiArrowDownSFill />,
    iconOpened: <RiArrowUpSFill />,
  
    subNav: [
      {
        title: "User List",
        path: "/user/list",
        icon: <IoIosPaper />,
        cName: "sub-nav",
      },
      {
        title: "User Roles",
        path: "/user/list",
        icon: <IoIosPaper />,
        cName: "sub-nav",
      },
     
    ],
  },
  {
    title: "Products",
    path: "/products",
    icon: <FaProductHunt />,
},
{
    title: "Events",
    path: "",
    icon: <FaEnvelopeOpenText />,
  
    iconClosed: <RiArrowDownSFill />,
    iconOpened: <RiArrowUpSFill />,
  
    subNav: [
      {
        title: "Event 1",
        path: "/events/events1",
        icon: <IoIosPaper />,
      },
      {
        title: "Event 2",
        path: "/events/events2",
        icon: <IoIosPaper />,
      },
    ],
  },
  {
    title: "About Us",
    path: "/about-us",
    icon: <AiFillHome />,
  },
  {
    title: "Contact",
    path: "/contact",
    icon: <FaPhone />,
  },
  
  {
    title: "Support",
    path: "/support",
    icon: <IoMdHelpCircle />,
  },
];


SubMenu.js
import React, { useState } from "react";
import Link from 'next/link';

const sidelink = {
  display: "flex",
  color: "#e1e9fc",
  justifyContent: "space-between",
  alignItems: "center",
  padding: "20px",
  listStyle: "none",
  height: "60px",
  textDecoration: "none",
  fontSize: "18px",
  
  hover :{
    background: "#252831",
    borderLeft: "4px solid green",
   cursor: "pointer",
 }
}

  
const SidebarLabel = {
  marginLeft: "16px",
}
  
const DropdownLink = {
  background: "#252831",
  height: "60px",
  paddingLeft: "3rem",
  display: "flex",
  alignItems: "center",
  textDecoration: "none",
  color: "#f5f5f5",
  fontSize: "18px",
  
  hover: {
    background: "green",
    cursor: "pointer"
  }
}

const SubMenu = ({ item }) => {
  const [subnav, setSubnav] = useState(false);
  
  const showSubnav = () => setSubnav(!subnav);
  
  return (
    <>
    <Link  href={{pathname:item.path}}>
      <a  style={sidelink} 
      onClick={item.subNav && showSubnav}>
        <div>
          {item.icon}
          <span style={{marginLeft: "10px"}}>{item.title}</span>
        </div>
        <div>
          {item.subNav && subnav
            ? item.iconOpened
            : item.subNav
            ? item.iconClosed
            : null}
        </div>
      </a>
      </Link>
      {subnav &&
        item.subNav.map((item, index) => {
          return (
            <Link  href={{pathname: item.path}}>
            <a key={index} style={DropdownLink} >
              {item.icon}
              <span style={SidebarLabel}>{item.title}</span>
            </a>
            </Link>
          );
        })}
    </>
  );
};
  
export default SubMenu;

In the components folder, create layout.js and layout.module.css files.
layout.js
import Head from 'next/head';
import styles from './layout.module.css';
import Sidebar from './sidebar/SideBar';

export const siteTitle = 'Next.js Sample Website';

export default function Layout(
  { 
    children, 
    title = 'Next.js sample',
    description = 'Next.js  sample project with sequelize & mysql database',
    keywords = 'Next.js, Sequelize, JWT, Json Web Tokens, Authentication, Application',
    token = '',
  }) 
  
  {
  
  
  return (
    <div className={styles.container}>
      <Head>
        <link rel="icon" href="/favicon.ico" />
        <meta charSet="utf-8" />
        <title>{title}</title>
        <link rel="icon" href="/favicon.ico" />
        
        <meta name="robots" content="index, follow" />
        <meta name="description" content={description} />
        <meta name="keywords" content={keywords} />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />
        

      </Head>
      <Sidebar token={token}/>    
      <header className={styles.header}>
        Welcome!
      </header>
      
      <main>{children}</main>
      </div>
  );
}

layout.module.css
.container {
    width: 100%;
    padding: 0 0rem;
    margin: 0rem auto 3rem;
  }
  
  .header {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

Modify the index.js file in pages folder to add Layout component:
import Layout from '../components/layout';

export default function Home() {
  return (
   
      <Layout 

          title='Home Page'
      />

  )
}

Then executing the following command to run the app.
npm run dev

By visiting http://localhost:3000/ you should see the following output:

Comments

Popular posts from this blog

Upload form data with file using Multer & MYSQL in NextJs

User Authentication: Register & Login using JWT in NextJs & MYSQL

NextJs & Mysql