Mobile Dropdown Design Next.js (CSS or Tailwind) - css

I want to make my mobile menu have a dropdown when the main labels are clicked as they do for the regular desktop navigation. The dropdown works for the mobile menu, but it displays it on the left side of the main label. What I want it to do is expand or toggle/show underneath the top label when clicked if that makes sense. An example would be the mobile menu here: https://www.youtube.com/watch?v=JEV7WE0UBiQ&t=2738s, but in my case, I only need to go one dropdown deep.
Here are my Navbar and Dropdown components for review. I also provided the relevant CSS as well.
I know there is much to be improved and there are other small errors I am getting, but if I can get help on this part, that would be great. I've actually been using the help of ChatGPT to assist with some things, but it can only get me so far. Sometimes it's great, and other times I just want to punch it, lol!
import React, { useState } from "react";
import Link from "next/link";
import Dropdown from "./Dropdown";
import { menuItems, mobileMenuItems } from "./MenuItems";
// Import the FontAwesomeIcon component
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
// import the icons you need
import {
faChevronDown,
faBars,
faXmark,
} from "#fortawesome/free-solid-svg-icons";
function Navbar() {
const [click, setClick] = useState(false);
const [dropdownOpen, setDropdownOpen] = useState({
dropdown1: false,
dropdown2: false,
dropdown3: false,
});
const handleClick = () => {
setClick(!click);
setDropdownOpen({ dropdown1: false, dropdown2: false, dropdown3: false });
};
const closeMobileMenu = () => {
setClick(false);
setDropdownOpen({ dropdown1: false, dropdown2: false, dropdown3: false });
};
const toggleDropdown = (dropdown) => {
if (window.innerWidth < 950) {
setDropdownOpen({ [dropdown]: !dropdownOpen[dropdown] });
} else {
setDropdownOpen({ [dropdown]: !dropdownOpen[dropdown] });
}
};
return (
<nav>
<div className="container mx-auto px-10 mb-8">
<div className="relative border-b w-full inline-block border-blue-400 py-8">
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
{/* Mobile menu button*/}
<button
className="inline-flex p-2 rounded-md text-gray-400 hover:text-white hover:bg-violet-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white text-3xl md:hidden"
onClick={() => {
setClick(!click);
}}
>
<FontAwesomeIcon icon={click ? faXmark : faBars} />
</button>
</div>
<div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
<div className="flex-1 flex flex-shrink-0 flex px-12 items-center ">
<h1 className="font-bold text-4xl cursor-pointer text-white">
My<span className="text-blue-500">site</span>
</h1>
</div>
<div className="hidden md:float-left md:contents">
<ul className="nav-menu">
{menuItems.map((link, index) => (
<li
key={index}
className="nav-item"
onMouseEnter={
link.dropdownType
? () => toggleDropdown(link.dropdownType)
: null
}
onMouseLeave={
link.dropdownType
? () => toggleDropdown(link.dropdownType)
: null
}
>
<Link href={link.href}>
<a className="menuItems nav-links">
{link.icon && (
<FontAwesomeIcon
className="px-2"
icon={link.icon}
style={{ fontSize: 20, color: link.color }}
/>
)}
{link.label}
{link.dropdownType && (
<span className="faChevronDown">
<FontAwesomeIcon
icon={faChevronDown}
></FontAwesomeIcon>
</span>
)}
</a>
</Link>
{link.dropdownType && dropdownOpen[link.dropdownType] && (
<Dropdown type={link.dropdownType} />
)}
</li>
))}
</ul>
</div>
</div>
</div>
</div>
{/* ----------------------Hamburger Menu----------------------- */}
<ul
className={click ? "mobileNav-menu active" : "sm:hidden mobileNav-menu"}
>
{mobileMenuItems.map((link, index) => (
<li key={index} className="nav-item">
<Link href={link.href}>
<a
onClick={
link.dropdownType
? () => toggleDropdown(link.dropdownType)
: closeMobileMenu
}
className="menuItems nav-links dropdown-toggle"
>
{link.icon && (
<FontAwesomeIcon
className="px-2"
icon={link.icon}
style={{ fontSize: 20, color: link.color }}
/>
)}
{link.label}
{link.dropdownType && (
<span className="faChevronDown">
<FontAwesomeIcon icon={faChevronDown}></FontAwesomeIcon>
</span>
)}
</a>
</Link>
{link.dropdownType && dropdownOpen[link.dropdownType] && (
<ul className="dropdown-menu">
<Dropdown type={link.dropdownType} onClick={closeMobileMenu} />
</ul>
)}
</li>
))}
</ul>
</nav>
);
}
export default Navbar;
and the Dropdown component
import React, { useState, useEffect } from "react";
import Link from "next/link";
import {
getFeaturedArticlesCategories,
getNewsCategories,
getReviewsCategories,
} from "../services";
function useCategories() {
const [categories, setCategories] = useState({
featured: [],
news: [],
reviews: [],
});
useEffect(() => {
let cancel = false;
const fetchCategories = async () => {
const featured = await getFeaturedArticlesCategories();
const news = await getNewsCategories();
const reviews = await getReviewsCategories();
if (!cancel) {
setCategories({ featured, news, reviews });
}
};
fetchCategories();
return () => {
cancel = true;
};
}, []);
return categories;
}
function Dropdown({ type, onClick }) {
const [click, setClick] = useState(false);
const categories = useCategories();
const handleClick = () => setClick(!click);
return (
<>
<ul
onClick={() => {
handleClick();
onClick();
}}
className={click ? "dropdown-menu clicked" : "dropdown-menu"}
>
{categories[type].map((item, { active }) => (
<Link href={`/${type}/${item.slug}`} key={item.slug}>
<a
className={`group flex justify-center items-center px-4 py-2 text-sm font-semibold cursor-pointer ${
active
? "text-gray-700"
: "menuItems hover:bg-indigo-500 transition-all duration-500 ease-in"
}`}
>
{item.name}
</a>
</Link>
))}
</ul>
</>
);
}
export default Dropdown;
and the CSS
//Nav Menu
.menuItems {
&:hover {
color: rgb(255, 0, 0);
}
}
.navbar {
width: 90%;
height: 6rem;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
padding-left: 2.5rem;
padding-right: 2.5rem;
margin-left: auto;
margin-right: auto;
margin-bottom: 5rem;
border-bottom-width: 1px;
border-color: #60a5fa;
}
.navbar-logo {
color: #fff;
justify-self: start;
margin-left: -1rem;
cursor: pointer;
text-decoration: none;
line-height: 2.5rem;
font-size: 2.25rem;
font-weight: 700;
}
.nav-menu {
display: grid;
grid-template-columns: repeat(5, auto);
grid-gap: 1rem;
list-style: none;
text-align: center;
width: 70vw;
justify-content: end;
margin-right: 2rem;
}
.nav-item {
display: flex;
align-items: center;
height: 4rem;
}
.nav-links {
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
display: inline-flex;
font-weight: 600;
justify-content: center;
width: 100%;
cursor: pointer;
}
.nav-links:hover {
background-color: #1888ff;
border-radius: 4px;
transition: all 0.2s ease-out;
}
.faBars {
color: #fff;
}
.nav-links-mobile {
display: none;
}
.menu-icon {
display: none;
}
#media screen and (max-width: 950px) {
.NavbarItems {
position: relative;
}
.mobileNav-menu {
display: flex;
flex-direction: column;
width: 100%;
height: 90vh;
position: absolute;
padding-top: 5rem;
padding-bottom: 15rem;
padding-left: 1rem;
bottom: 0;
top: 5rem;
left: -100%;
opacity: 1;
transition: all 0.5s ease;
}
.mobileNav-menu.active {
background: #242222;
left: 0;
opacity: 1;
transition: all 0.5s ease;
z-index: 1;
}
.nav-links {
text-align: center;
padding: 2rem;
width: 100%;
display: table;
}
.nav-links:hover {
background-color: #1888ff;
border-radius: 0;
}
.navbar-logo {
position: absolute;
top: 0;
left: 0;
transform: translate(25%, 50%);
}
.menu-icon {
display: block;
position: absolute;
top: 0;
right: 0;
transform: translate(-100%, 60%);
font-size: 1.8rem;
cursor: pointer;
}
.faXmark {
color: #fff;
font-size: 2rem;
}
.faChevronDown {
margin-left: 0.5rem;
padding: 0.5rem;
}
.nav-links-mobile {
display: block;
text-align: center;
padding: 1.5rem;
margin: 2rem auto;
border-radius: 4px;
width: 80%;
background: #1888ff;
text-decoration: none;
color: #fff;
font-size: 1.5rem;
}
.nav-links-mobile:hover {
background: #fff;
color: #1888ff;
transition: 250ms;
}
}
//Dropdown
.dropdown-menu {
background: rgb(184, 183, 231);
width: 10rem;
position: absolute;
border-radius: 0.375rem;
top: 6rem;
list-style: none;
text-align: start;
z-index: 10;
}
.dropdown-menu li {
background: #1888ff;
cursor: pointer;
}
.dropdown-menu li:hover {
background: #5cabff;
}
.dropdown-menu.clicked {
display: none;
}
.dropdown-link {
display: block;
height: 100%;
width: 100%;
text-decoration: none;
color: #fff;
padding: 16px;
}

Related

Converting a react made responsive navbar into nextjs navbar

I am trying to convert a react made responsive navbar component into next js navbar component. I don't know much about next js. Can anyone help with this code.The responsiveness works just fine. However, I cannot close the hamburger menu once I clicked it. The issue is with close Hamburger menu button. Here is the navbar component code converted from React js app:
import React from 'react';
import React from 'react';
import { GiHamburgerMenu } from 'react-icons/gi';
import { MdOutlineRestaurantMenu } from 'react-icons/md';
import Image from "next/image";
import styles from "../styles/Navbar.module.css"
const Navbar = () => {
const [toggleMenu, setToggleMenu] = React.useState(false);
return (
<nav className={styles.app__navbar}>
<div className={styles.app__navbar_logo}>
<Image src="/img/ephielogo.png" alt="app__logo" />
</div>
<ul className={styles.app__navbar_links}>
<li className={styles.p__opensans}>Home</li>
<li className={styles.p__opensans}>About</li>
<li className={styles.p__opensans}>Menu</li>
<li className={styles.p__opensans}>Awards</li>
<li className={styles.p__opensans}>Contact</li>
</ul>
<div className={styles.app__navbar_login}>
<a href="#login" className={styles.p__opensans}>Log In / Registration</a>
<div />
<a href="/" className={styles.p__opensans}>Book Table</a>
</div>
<div className={styles.app__navbar_smallscreen}>
<GiHamburgerMenu color="#fff" fontSize={27} onClick={() => setToggleMenu(true)} />
{toggleMenu && (
<div className={styles["app__navbar_smallscreen_overlay"] + " " + styles["flex__center"] + styles["slide_bottom"]}>
<MdOutlineRestaurantMenu fontSize={27} className="overlay__close" onClick={() => setToggleMenu(false)} />
<ul className={styles.app__navbar_smallscreen_links}>
<li><a href="#home" onClick={() => setToggleMenu(false)}>Home</a></li>
<li><a href="#about" onClick={() => setToggleMenu(false)}>About</a></li>
<li><a href="#menu" onClick={() => setToggleMenu(false)}>Menu</a></li>
<li><a href="#awards" onClick={() => setToggleMenu(false)}>Awards</a></li>
<li><a href="#contact" onClick={() => setToggleMenu(false)}>Contact</a></li>
</ul>
</div>
)}
</div>
</nav>
);
};
export default Navbar;
Here is my Navbar.Module.css code.
.app__navbar {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
background: var(--color-black);
padding: 1rem 2rem;
}
.app__navbar_logo {
display: flex;
justify-content: flex-start;
align-items: center;
}
.app__navbar_logo img {
width: 150px;
}
.app__navbar_links {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
color: var(--color-white);
list-style: none;
}
.app__navbar_links li {
margin: 0 1rem;
cursor: pointer;
}
.app__navbar_links li:hover {
color: var(--color-grey);
}
.app__navbar_login {
display: flex;
justify-content: flex-end;
align-items: center;
}
.app__navbar_login a {
margin: 0 1rem;
text-decoration: none;
transition: .5s ease;
color: var(--color-white)
}
.app__navbar_login a:hover {
border-bottom: 1px solid var(--color-golden);
}
.app__navbar_login div {
width: 1px;
height: 30px;
background: var(--color-grey);
}
.app__navbar_smallscreen {
display: none;
}
.app__navbar_smallscreen_overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: var(--color-black);
transition: .5s ease;
flex-direction: column;
z-index: 5;
}
.app__navbar_smallscreen_overlay .overlay__close {
font-size: 27px;
color: var(--color-golden);
cursor: pointer;
position: absolute;
top: 20px;
right: 20px;
}
.app__navbar_smallscreen_links {
list-style: none;
}
.app__navbar_smallscreen_links li {
margin: 2rem;
cursor: pointer;
color: var(--color-golden);
font-size: 2rem;
text-align: center;
font-family: var(--font-base);
}
.app__navbar_smallscreen_links li:hover {
color: var(--color-white);
}
#media screen and (min-width: 2000px) {
.app__navbar_logo img {
width: 210px;
}
}
#media screen and (max-width: 1150px) {
.app__navbar_links {
display: none;
}
.app__navbar_smallscreen {
display: flex;
}
}
#media screen and (max-width: 650px) {
.app__navbar {
padding: 1rem;
}
.app__navbar_login {
display: none;
}
.app__navbar_logo img {
width: 110px;
}
}

Hiding Side Nav in Hamburger Menu

I have a sidebar, that I would like to collpase on mobile devices, and only be accessed on mobile using a hamburger menu
Using React, what is the best way for me to do so? Would this still be media queriers, or is there an alternate way that would make this type of configuration more seamless?
Please note that I only want the sidebar to collapse on mobile. I do not want to give the user the ability to collpase the sidebar when viewed on desktop.
Sidebar.Js
const sidebarNavItems = [
{
display: 'Home',
to: '/'
},
{
display: 'Blog',
to: 'Blog/'
},
{
display: 'Contact Us',
to: '/contact-us/'
},
{
display: 'Sign Up',
to: '/sign-up/'
},
{
display: 'Login',
to: '/sign-in/'
},
]
const Sidebar = () => {
const [activeIndex, setActiveIndex] = useState(0);
const [stepHeight, setStepHeight] = useState(0);
const sidebarRef = useRef();
const indicatorRef = useRef();
const location = useLocation();
useEffect(() => {
setTimeout(() => {
const sidebarItem = sidebarRef.current.querySelector('.sidebar__menu__item');
indicatorRef.current.style.height = `${sidebarItem.clientHeight}px`;
setStepHeight(sidebarItem.clientHeight);
}, 50);
}, []);
// change active index
useEffect(() => {
const curPath = window.location.pathname.split('/')[1];
const activeItem = sidebarNavItems.findIndex(item => item.section === curPath);
setActiveIndex(curPath.length === 0 ? 0 : activeItem);
}, [location]);
return (
<div className='sidebar'>
<div className="sidebar__logo">
<div><img src = {Logo} alt='Logo'className='Logo' /></div>
</div>
<div ref={sidebarRef} className="sidebar__menu">
<div
ref={indicatorRef}
className="sidebar__menu__indicator"
style={{
transform: `translateX(-50%) translateY(${activeIndex * stepHeight}px)`
}}
></div>
{
sidebarNavItems.map((item, index) => (
<Link to={item.to} key={index}>
<div className={`sidebar__menu__item ${activeIndex === index ? 'active' : ''}`}>
<div className="sidebar__menu__item__icon">
{item.icon}
</div>
<div className="sidebar__menu__item__text">
{item.display}
</div>
</div>
</Link>
))
}
</div>
</div>);
};
Here is the Sidebar.CSS
.sidebar {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 20vw;
background-color: #fff;
}
.sidebar__logo {
display: grid;
place-items: center;
margin-bottom: 5vh;
}
.sidebar__menu {
position: relative;
}
.sidebar__menu__item {
display: flex;
align-items: center;
place-content: flex-start;
padding: 1rem 3rem;
font-size: 1.25rem;
font-weight: 500;
color: #555;
transition: color 0.3s ease-in-out;
}
.sidebar__menu__item.active {
color: #fff;
}
.sidebar__menu__item__icon {
margin-right: 1rem;
}
.sidebar__menu__item__icon i {
font-size: 1.75rem;
}
.sidebar__menu__indicator {
position: absolute;
top: 0;
left: 50%;
width: calc(100% - 40px);
border-radius: 5px;
background-color: #FD954E;
z-index: -1;
transform: translateX(-50%);
transition: 0.3s ease-in-out;
}

Navbar covering the full width of screen

I am making a dashboard for my project in which I am also including navbar in it , but when I included navbar , it is covering the whole length of the screen . I tried a lot , but I am not that much pro in css , can anyone correct this code ??
Here is my dashboard code :
import React from 'react';
import Navbar from './components/Navbar/Navbar';
import RightNavbar from './components/RightNavbar/RightNavbar';
import styles from './App.module.scss';
function App({ history }) {
return (
<div>
<Navbar/>
<RightNavbar/>
<ToastContainer />
<div className = {styles.container}>
</div>
</div>
);
}
export default App;
Here is my Navbar code :
//STYLES
import styles from "./Navbar.module.scss";
//CONTEXT
import { useContext } from "react";
import NavContext from "../../Context/NavContext";
//REACT ROUTER
import { NavLink } from "react-router-dom";
//ICONS
import {
MdOutlineDashboard,
MdOutlineAnalytics,
MdOutlinedFlag,
MdPeopleOutline,
MdOutlineMessage,
MdOutlineLogout,
} from "react-icons/md";
import { IoMdLogIn } from "react-icons/io";
import { FaReact, FaTimes } from "react-icons/fa";
import { BsThreeDots } from "react-icons/bs";
import { VscDashboard } from "react-icons/vsc";
const NavUrl = ({ url, icon, description }) => {
const { nav, setNav } = useContext(NavContext);
const checkWindowSize = () => {
if (window.innerWidth < 1024) setNav(!nav);
};
return (
<li className={styles.li_navlink}>
<NavLink
to={`${url}`}
className={({ isActive }) => (isActive ? styles.active : undefined)}
onClick={() => checkWindowSize()}
>
{icon}
<span className={styles.description}>{description}</span>
</NavLink>
</li>
);
};
const Navbar = () => {
const { nav, setNav } = useContext(NavContext);
return (
<div
className={`${styles.navbar_container} ${
nav ? styles.navbar_mobile_active : undefined
}`}
>
<nav className={nav ? undefined : styles.nav_small}>
{/* LOGO */}
<div className={styles.logo}>
<VscDashboard className={styles.logo_icon} />
<FaTimes
className={styles.mobile_cancel_icon}
onClick={() => {
setNav(!nav);
}}
/>
</div>
{/* MENU */}
<ul className={styles.menu_container}>
{/* FIRST CATEGORY */}
<span className={styles.categories}>
{nav ? "Pages" : <BsThreeDots />}
</span>
<NavUrl
url="/"
icon={<MdOutlineDashboard />}
description="Dashboard"
/>
<NavUrl
url="analytics"
icon={<MdOutlineAnalytics />}
description="Analytics"
/>
<NavUrl
url="campaings"
icon={<MdOutlinedFlag />}
description="Campaings"
/>
<NavUrl url="team" icon={<MdPeopleOutline />} description="Team" />
<NavUrl
url="messages"
icon={<MdOutlineMessage />}
description="Messages"
/>
</ul>
{/* LOGOUT BUTTON */}
<div
className={`${styles.btn_logout}`}
onClick={() => {
setNav(!nav);
}}
>
<MdOutlineLogout />
</div>
</nav>
<div
className={nav ? styles.mobile_nav_background_active : undefined}
onClick={() => {
setNav(!nav);
}}
></div>
</div>
);
};
export default Navbar;
And here is my Navbar.module.scss :
.navbar_container {
--color_nav_bg: rgb(30, 41, 59);
--color_nav_txt: rgb(100, 116, 139);
--color_nav_ctg: rgb(226, 232, 240);
--color_nav_active: rgb(85, 79, 232);
--color_nav_not_active: rgb(61, 74, 94);
--color_nav_active_bg: rgb(15, 23, 42);
--nav_width: 16rem;
background: var(--color_nav_bg);
height: 100vh;
padding: var(--padding-md) var(--padding-sm);
transition: transform 300ms ease-in-out;
#media screen and (max-width: 1024px) {
transform: translateX(-100%);
position: absolute;
top: 0;
left: 0;
z-index: 12;
}
#media screen and (max-width: 18rem) {
width: 100vw;
}
}
.navbar_mobile_active {
#media screen and (max-width: 1024px) {
transform: translateX(0);
}
}
nav {
position: relative;
width: var(--nav_width);
height: 100%;
display: flex;
flex-direction: column;
overflow-y: scroll;
overflow-x: hidden;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
transition: width linear 0.3s;
&::-webkit-scrollbar {
display: none;
}
}
.logo {
padding: 0 0.35rem;
font-size: 2.2rem;
display: flex;
.logo_icon {
color: var(--color_nav_active);
}
.mobile_cancel_icon {
display: none;
}
#media screen and (max-width: 1024px) {
.logo_icon {
display: none;
}
.mobile_cancel_icon {
display: block;
cursor: pointer;
font-size: 2.2rem;
padding: 0.2rem;
color: var(--color_nav_active);
}
}
}
.menu_container {
margin-top: var(--margin-lg);
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.categories {
color: var(--color_nav_txt);
text-transform: uppercase;
font-size: 0.8rem;
margin-bottom: var(--margin-xxs);
svg {
font-size: 1rem;
}
}
.second_category {
margin-top: 3rem;
}
.li_navlink a {
display: flex;
align-items: center;
flex: 1;
padding: 0.5rem 0.75rem;
text-decoration: none;
color: var(--color_nav_ctg);
transition: all ease-in-out 0.2s;
.description {
margin-left: 0.5rem;
font-weight: 400;
transition: opacity 200ms ease;
}
svg {
font-size: 1.5rem;
color: var(--color_nav_not_active);
flex-shrink: 0;
}
&:hover {
background: var(--color_nav_active_bg);
}
&:hover svg {
color: var(--color_nav_active);
}
}
.li_navlink .active {
background: var(--color_nav_active_bg);
svg {
color: var(--color_nav_active);
}
}
.btn_logout {
margin-top: auto;
display: flex;
justify-content: flex-end;
transition: all ease-in-out 200ms;
padding: 0.5rem 0.75rem 0 0.75rem;
svg {
font-size: 1.5rem;
color: var(--color_nav_active);
cursor: pointer;
transform: scaleX(-1);
}
}
.mobile_nav_background_active {
width: 0;
height: 100vh;
transition: all ease-out 500ms;
transition-delay: 300ms;
cursor: pointer;
#media screen and (max-width: 1024px) {
display: block;
position: absolute;
top: 0;
left: calc(var(--nav_width) + var(--padding-md));
width: calc(100vw - var(--nav_width) - var(--padding-md));
background: rgba(0, 0, 0, 0.185);
z-index: -1;
}
}
//NAVIGATION SMALL
.nav_small {
width: 3rem;
.categories {
padding: 0 1rem;
}
.description {
opacity: 0;
}
.btn_logout {
svg {
transform: scaleX(1);
}
}
}

How make a verticale smooth transition in CSS with react component?

I try to make a smooth transition for my hamburger menu, but I don't find solution to do it... I'm not really fluid with the CSS and it's very difficult to find a good example on the web or a good tutorial to explain the process.
below my code, I hope it's enough simple to understand my problem.
a link to the project https://github.com/StanLepunK/cafe366/blob/stan/src/components/menu/menu_small.js
export const MenuSmallImpl = () => {
let res = Get_window();
const [width, set_width] = useState(res[0]/2);
const [open, set_open] = useState(false);
const toggleMenu = () => {
set_open(!open);
}
return (
<Fragment>
<div className={nav_bar}>
<button
onClick={() => toggleMenu()}
className={toggle_menu}
>
<div className={hamburger_container}>
<div className={hamburger}>
<div className={[burger, "burger1"].join(" ")} />
<div className={[burger, "burger2"].join(" ")} />
<div className={[burger, "burger3"].join(" ")} />
</div>
<style>{`
.burger1 {
transform: ${ open ? 'rotate(45deg)' : 'rotate(0)'};
}
.burger2 {
opacity: ${ open ? 0 : 1};
}
.burger3 {
transform: ${ open ? 'rotate(-45deg)' : 'rotate(0)'};
}
`}</style>
</div>
</button>
<div>{open ? <div className={show}><MenuContent /></div> : <div className={hidden}><MenuContent /></div> }</div>
</div>
</Fragment>
)
}
.nav_bar {
text-align: center;
border-radius: 0;
background-color: rgb(var(--orange_366_rgb));
transition: height 3s ease;
}
.nav_bar .show {
height: 100%;
overflow: visible;
}
.nav_bar .hidden {
height: 0;
overflow: hidden;
}
.nav_bar:active {
height: 100%;
overflow: visible;
}
.toggle_menu {
height: 50px;
width: 50px;
z-index: 1;
}
.hamburger_container {
display: flex;
justify-content: center;
align-items: center;
}
.hamburger{
width: 2rem;
height: 2rem;
display: flex;
justify-content: space-around;
flex-flow: column nowrap;
}
.burger{
width: 2rem;
height: 2px;
border-radius: 2px;
background-color: rgb(var(--lin_rgb));
transform-origin: 1px;
transition: all 0.3s linear;
}
CODE IMPROVED on the advice John Ruddell, but it's not enough, that's work but not totally only for the text not for the frame. See here use a small window to see the hamburger menu https://cafe366stan.gatsbyjs.io/
I don't understand why the text move and not the frame...
my new code
JS
import React, { useState, Fragment } from "react"
// CAFÉ 366
import MenuContent from "./menu_content"
import { nav_bar, toggle_menu, content_menu_small,
hamburger, burger, hamburger_container,
show, hidden } from "./menu_small.module.css";
// UTILS
import { Get_window } from "../../utils/canvas"
export const MenuSmallImpl = () => {
const [open, set_open] = useState(false);
const toggleMenu = () => {
set_open(!open);
}
return (
<Fragment>
<div style={{textAlign:`center`}}>
<button
onClick={() => toggleMenu()}
className={toggle_menu}
>
<div className={hamburger_container}>
<div className={hamburger}>
<div className={[burger, "burger1"].join(" ")} />
<div className={[burger, "burger2"].join(" ")} />
<div className={[burger, "burger3"].join(" ")} />
</div>
<style>{`
.burger1 {
transform: ${ open ? 'rotate(45deg)' : 'rotate(0)'};
}
.burger2 {
opacity: ${ open ? 0 : 1};
}
.burger3 {
transform: ${ open ? 'rotate(-45deg)' : 'rotate(0)'};
}
`}</style>
</div>
</button>
</div>
<div className={[nav_bar, "move"].join(" ")}>
{/* <div>{open ? <div className={show}><MenuContent /></div> : <div className={hidden}><MenuContent /></div> }</div> */}
<MenuContent />
</div>
<style>{`
.move {
transform: ${open ? 'translatey(0)' : 'translatey(-400px)'};
}
`}</style>
</Fragment>
)
}
export default function MenuSmall() {
return (
<MenuSmallImpl/>
)
}
CSS
.nav_bar {
height: 0%;
text-align: center;
border-radius: 0;
background-color: rgb(var(--orange_366_rgb));
transition: 1s ease;
/* border-right: 1px solid; */
}
.nav_bar .show {
height: 100%;
overflow: visible;
}
.nav_bar .hidden {
height: 0;
overflow: hidden;
}
.nav_bar:active {
height: 100%;
overflow: visible;
}
.toggle_menu {
height: 50px;
width: 50px;
z-index: 1;
/* border: solid 1px white; */
}
.hamburger_container {
display: flex;
justify-content: center;
align-items: center;
}
.hamburger{
width: 2rem;
height: 2rem;
display: flex;
justify-content: space-around;
flex-flow: column nowrap;
/* border: solid 1px white; */
}
.burger{
width: 2rem;
height: 2px;
border-radius: 2px;
background-color: rgb(var(--lin_rgb));
transform-origin: 1px;
transition: all 0.3s linear;
}
and two screenshots to understand my goal
now when it's deploy

Custom style on navbar when a section is active on the same page in Gatsby

I am trying to create a simple landing page with React. As per the title I have tried to get the active section heading (in the navbar) to be highlighted (change color) when the user scrolls to that section on the page, no success so far even after searching online for a long time. Really stuck. Following the tutorial, I am using styled-components for styling, different files for each component. Here is the code for my Navbar:
import React, { useState, useEffect } from 'react'
import styled from 'styled-components'
import { FaBars, FaTimes } from 'react-icons/fa'
import { IconContext } from 'react-icons/lib'
import { Link } from 'gatsby'
import Icon from '../images/Icon.png'
import { ButtonOne } from './Button'
import ScrollSpy from 'react-scrollspy-navigation';
import './layout.css'
const Navbar = () => {
const [click, setClick] = useState(false)
const [scroll, setScroll] = useState(false)
const handleClick = () => setClick(!click)
const changeNav = () => {
if (window.scrollY >= 130){
setScroll(true)
} else {
setScroll(false)
}
}
useEffect(() => {
changeNav()
window.addEventListener('scroll', changeNav)
}, [])
return (
<>
<IconContext.Provider value={{ color: '#fabf49'}}>
<Nav active={scroll} click={click}>
<NavbarContainer>
<NavLogo to='/'>
<NavIcon>
<img src={Icon} height={100} width={100} alt='Icon' />
</NavIcon>
</NavLogo>
<MobileIcon onClick={handleClick}>{click ? <FaTimes /> : <FaBars />}</MobileIcon>
<NavMenu onClick={handleClick} click={click}>
<ScrollSpy offsetTop={80} duration={1500}>
<a href='/#s1' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s1' activeClassName={`active`}>Company</NavLinks>
</NavItem>
</a>
<a href='#s4' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s4' activeClassName={`active`}>Features</NavLinks>
</NavItem>
</a>
<a href='#s7' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s7' activeClassName={`active`} >Partners</NavLinks>
</NavItem>
</a>
<a href='#s6' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s6' activeClassName={`active`}>Updates</NavLinks>
</NavItem>
</a>
<a href='#s8' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s8' activeClassName={`active`}>Careers</NavLinks>
</NavItem>
</a>
<a href='#s8' ref={React.createRef()}>
<NavItem>
<NavLinks to='/#s8' activeClassName={`active`}>Contact Us</NavLinks>
</NavItem>
</a>
<NavBtn>
<ButtonOne a href='#s8' ref={React.createRef()} style={{scrollBehavior: "smooth"}}>BOOK NOW</ButtonOne>
</NavBtn>
</ScrollSpy>
</NavMenu>
</NavbarContainer>
</Nav>
</IconContext.Provider>
</>
)
}
export default Navbar
const Nav = styled.div`
background: ${({ active }) => (active ? '#1b2227' : 'transparent')};
height: 80px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
position: sticky;
top: 0;
z-index: 999;
#media screen and (max-width: 1120px) {
background: ${({ click }) => (click ? '#1b2227' : 'transparent')};
transition: 0.8s all ease;
position: sticky;
background: ${({ active }) => (active ? '#1b2227' : 'transparent')};
height: 80px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
position: sticky;
top: 0;
z-index: 999;
}
`
const NavbarContainer = styled.div`
display: flex;
justify-content: space-between;
height: 80px;
z-index: 1;
width: 100%;
`
const NavLogo = styled(Link)`
color: white;
justify-content: flex-start;
cursor: pointer;
text-decoration: none;
font-size: 1.5rem;
display: flex;
align-items: center;
margin-left: 2.5rem;
`
const NavIcon = styled.div`
margin: 0 0.5rem 0 2rem;
`
const MobileIcon = styled.div`
display: none;
#media screen and (max-width: 1120px) {
display: block;
position: absolute;
top: 0;
right: 0;
transform: translate(-100%, 60%);
font-size: 1.8rem;
cursor: pointer;
}
`
const NavMenu = styled.ul`
display: flex;
align-items: center;
list-style: none;
text-align: center;
#media screen and (max-width: 1120px) {
display: flex;
flex-direction: column;
width: 100%;
height: 90vh;
position: absolute;
top: ${({ click }) => (click ? '100%' : '-1000px')};
opacity: 1;
transition: all 0.2s ease;
background: #1b2227;
color: #fabf49;
}
`
const NavLinks = styled(Link)`
color: #fff;
display: flex;
align-items: center;
text-decoration: none;
padding: 0.5rem 1rem;
height: 100%;
&:hover {
color: #fabf49;
}
#media screen and (max-width: 1120px) {
text-align: center;
padding: 2rem;
width: 100%;
display: table;
color: #fabf49;
&:hover {
color: white;
transition: all 0.3s ease;
}
}
`
const NavItem = styled.li`
height: 80px;
margin-right: 2rem;
#media screen and (max-width: 1120px) {
width: 100%;
}
`
const NavBtn = styled.div`
display: flex;
align-items: center;
margin-right: 3rem;
#media screen and (max-width: 1120px) {
display: none;
}
`
and here is my index page where all the different sections are assembled into the landing page:
import * as React from "react"
import Layout from "../components/layout"
import Seo from "../components/seo"
import Hero from "../components/Hero"
import SectionTwo from "../components/SectionTwo"
import SectionThree from "../components/SectionThree"
import SectionFour from "../components/SectionFour"
import SectionFive from "../components/SectionFive"
import SectionSix from "../components/SectionSix"
import Partners from "../components/Partners"
const IndexPage = () => (
<Layout>
<Seo title="CARNIVAL" />
<section id='s1'><Hero /></section>
<section id='s2'><SectionTwo /></section>
<section id='s3'><SectionThree /></section>
<section id='s4'><SectionFour /></section>
<section id='s5'><SectionFive /></section>
<section id='s6'><SectionSix /></section>
<section id='s7'><Partners /></section>
</Layout>
)
export default IndexPage
For additional info here is the Layout component:
import * as React from "react"
import Footer from "./Footer"
import { GlobaStyle } from "./GlobalStyles"
import Navbar from "./Navbar"
const Layout = ({ children }) => {
return (
<>
<GlobaStyle />
<Navbar />
<main>{children}</main>
<section id='s8'><Footer /></section>
</>
)
}
export default Layout
and the css file (many related answers have a css file so I tried that too):
.active{
color: #fabf49;
}
I have managed to get the scrollspy working, however I am stuck on the active part being highlighted/custom styled in the navbar.

Resources