Hey Devs! 🌼
I am a dev scholar, and I want to begin producing content material that may assist different folks. Since I am beginning within the dev group, I can relate to many difficulties that starters have, and I do know that a few of them appear too easy and do not even have content material explanations on the web.
At the moment I might be serving to you to create a menu identical to the one within the cowl gif. As a bônus, I additionally set the present web page with a unique shade on the nav bar. On this article, I will be utilizing a React utility, which suggests a number of the processes could also be totally different in case you’re utilizing a unique sort of framework (or none in any respect). To create the logic that adjustments the web page type, I will use React Hooks.
The venture is on the market on this repository, to make use of it you simply have to observe the directions within the README file. Additionally, there may be deploy with the end result if you wish to see it.
I like to make use of this characteristic in my initiatives, nonetheless, I’ve by no means seen a tutorial explaining the best way to. So let’s get began!😄
1. Putting in Tailwind in your venture
So, very first thing, you could set up Tailwind. I like to recommend you take a look at the documentation (aka your finest pal when coding).
2. Create the part
Now, it’s important to create the menu part. After I use React, I favor to make it aside and add it to the pages. Right here is an instance of a navigation menu that I produced in my timer’s venture.
// part: Nav
import brand from '../belongings/photos/icon.png'
import Button from '../elements/Button';
import LinkComponent from "./LinkComponent";
const Nav = () => {
return (
<nav>
<Button
func={() => setIsOpen(!isOpen)}
txt={<img alt="menu-burguer" src={brand} />}
/>
<div>
<LinkComponent path={"/"} txt={"House Web page"} />
<LinkComponent path={"/countdown"} txt={"Countdown"} />
<LinkComponent path={"/timer"} txt={"Timer"} />
<LinkComponent path={"/settings"} txt={"Settings"} />
<LinkComponent path={"/about"} txt={"About"} />
</div>
</nav>
);
}
export default Nav;
// part: Button
const Button = ({ func, txt, isDisabled, className }) => {
return (
<button
className={className}
disabled={isDisabled}
kind="button"
onClick={ func }
>
{ txt }
</button>
);
}
Button.defaultProps = {
isDisabled: false,
}
export default Button;
// part: LinkComponent
import { Hyperlink } from "react-router-dom"
const LinkComponent = ({ path, txt }) => {
return (
<Hyperlink
to={path}
>
{txt}
</Hyperlink>
);
}
export default LinkComponent;
3. Create the logic
For this animation to work as we count on, it’s a necessity to have a code that enables a change of the HTML courses. That’s necessary since you want a unique animation when opening and shutting de menu, in addition to, it is elementary that the place set to the bar is the one the place it is supposed to remain when the animation is over.
// part: Nav
import { useState } from "react";
import brand from '../belongings/photos/icon.png'
import Button from '../elements/Button';
import LinkComponent from "./LinkComponent";
const Nav = () => {
// the state used to alter the present state of affairs (open or closed)
const [isOpen, setIsOpen] = useState(false);
return (
<nav>
<Button
// when the "menu" button is clicked, it units the state for the other boolean worth
func={() => setIsOpen(!isOpen)}
txt={<img alt="menu-burguer" src={brand} />}
/>
// that is the div the place the menu is "hidden", so it is the place the change of courses must occur
<div
className={isOpen ? ('class for open menu') : ('class for closed menu')}
>
<LinkComponent path={"/"} txt={"House Web page"} />
<LinkComponent path={"/countdown"} txt={"Countdown"} />
<LinkComponent path={"/timer"} txt={"Timer"} />
<LinkComponent path={"/settings"} txt={"Settings"} />
<LinkComponent path={"/about"} txt={"About"} />
</div>
</nav>
);
}
export default Nav;
The bonus half, the place the hyperlink to the present web page is highlighted, it’s kind of extra difficult, because it wants extra logic.
// part: LinkComponent
import { useContext, useEffect, useState } from "react";
import { Hyperlink, useRouteMatch } from "react-router-dom"
import TimeContext from "../context/TimeContext";
const LinkComponent = ({ path, txt }) => {
// first, we have to get the present pathname
const pathname = useRouteMatch();
const [isCurrent, setIsCurent] = useState(false);
const [currentPath, setCurrentPath] = useState('/');
// all the time when the pathname is modified the operate happens
useEffect(() => {
setCurrentPath(pathname.path)
}, [pathname]);
// all the time when the pathname or the trail (props) is modified the operate happens
useEffect(() => {
const changeIsCurrent = () => {
if (currentPath === path) {
setIsCurent(true);
} else {
setIsCurent(false);
}
}
changeIsCurrent();
}, [currentPath, path]);
return (
// the place occurs the spotlight relies upon if it is true (occur) or false (do not occur)
<Hyperlink
className={isCurrent ? ('class when the web page is the present'): ('class when the web page will not be the present')}
to={path}
>
{txt}
</Hyperlink>
);
}
export default LinkComponent;
4. Create the animation
Within the doc tailwind.config.js, there’s an object the place you possibly can add your customized settings. We will add our animation config, identical to the instance.
// tailwind.config.js
/** @kind {import('tailwindcss').Config} */
module.exports = {
content material: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: {
lengthen: {
animation: {
openmenu: 'openmenu 1s ease-in',
closemenu: 'closemenu 1s ease-in',
},
keyframes: {
openmenu: {
// preliminary place
'0%': {left: '-224px'},
// last place
'100%': {left: '0px'}
},
closemenu: {
// preliminary place
'0%': {left: '0px'},
// last place
'100%': {left: '-224px'}
},
}
},
},
plugins: [],
}
5. Add the courses to the menu part
Now that you’ve got your animation, it is time to add it to the part. This one is the results of my timer’s venture, however you possibly can type it the way in which you want.
Alert: Remember to set the last place
from the animation because the default
in your part. That’s vital as a result of as soon as the animation is over, it’s going to be redirected to the place set.
// part: Nav
import { useState } from "react";
import brand from '../belongings/photos/icon.png'
import Button from '../elements/Button';
import LinkComponent from "./LinkComponent";
const Nav = () => {
const [isOpen, setIsOpen] = useState(false);
return (
<nav className="font-epilogue">
<Button
className="w-20"
func={() => setIsOpen(!isOpen)}
txt={<img alt="menu-burguer" src={brand} />}
/>
<div
className={isOpen ?
"left-[0px] font-epilogue flex top-[12vh] animate-openmenu w-56 absolute flex-col bg-light-ocean p-12 h-[88vh]" :
"animate-closemenu top-[12vh] left-[-224px] flex w-56 absolute flex-col bg-light-ocean p-12 h-[88vh]"}
>
<LinkComponent path={"/"} txt={"House Web page"} />
<LinkComponent path={"/countdown"} txt={"Countdown"} />
<LinkComponent path={"/timer"} txt={"Timer"} />
<LinkComponent path={"/settings"} txt={"Settings"} />
<LinkComponent path={"/about"} txt={"About"} />
</div>
</nav>
);
}
export default Nav;
// part: LinkComponent
import { useContext, useEffect, useState } from "react";
import { Hyperlink, useRouteMatch } from "react-router-dom"
import TimeContext from "../context/TimeContext";
const LinkComponent = ({ path, txt }) => {
const pathname = useRouteMatch();
const { currentPath } = useContext(TimeContext);
const [isCurrent, setIsCurent] = useState(false);
const [currentPath, setCurrentPath] = useState('/');
useEffect(() => {
setCurrentPath(pathname.path)
}, [pathname]);
useEffect(() => {
const changeIsCurrent = () => {
if (currentPath === path) {
setIsCurent(true);
} else {
setIsCurent(false);
}
}
changeIsCurrent();
}, [currentPath, path]);
return (
<Hyperlink
className={isCurrent ? (
"mb-3 text-dark-purple font-bold bg-soft-purple p-2 text-center rounded-2xl"): (
"mb-3 text-dark-purple hover:font-bold p-2 text-center")}
to={path}
>
{txt}
</Hyperlink>
);
}
export default LinkComponent;
I hope I’ve loved this tutorial. When you see one thing that may be improved, do not hesitate to get in contact with me! All suggestions may be very welcome.✨