nav menu wave
This commit is contained in:
1
src/img/menu-wave.svg
Normal file
1
src/img/menu-wave.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"><path fill="#282c34" fill-opacity="1" d="M0,32L60,37.3C120,43,240,53,360,64C480,75,600,85,720,106.7C840,128,960,160,1080,160C1200,160,1320,128,1380,112L1440,96L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 330 B |
30
src/nav/Menu.tsx
Normal file
30
src/nav/Menu.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import "./menu.scss";
|
||||||
|
import {motion, animate} from "framer-motion";
|
||||||
|
import {useEffect} from "react";
|
||||||
|
|
||||||
|
const articles = [
|
||||||
|
"Test 123",
|
||||||
|
"Hello",
|
||||||
|
"Title of Album"
|
||||||
|
];
|
||||||
|
const hidden = -999;
|
||||||
|
|
||||||
|
export function Menu({active} : {active: boolean}) {
|
||||||
|
useEffect(() => {
|
||||||
|
if(active) {
|
||||||
|
animate(".menu", {left : 0})
|
||||||
|
} else {
|
||||||
|
animate(".menu", {left : hidden})
|
||||||
|
}
|
||||||
|
}, [active]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.section className="menu">
|
||||||
|
{
|
||||||
|
articles.map(title => <div>
|
||||||
|
{title}
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
</motion.section>
|
||||||
|
)
|
||||||
|
}
|
||||||
42
src/nav/Nav.tsx
Normal file
42
src/nav/Nav.tsx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
|
import {faBars} from "@fortawesome/free-solid-svg-icons/faBars";
|
||||||
|
import {Menu} from "./Menu";
|
||||||
|
import wave from "../img/menu-wave.svg";
|
||||||
|
import "./nav.scss";
|
||||||
|
import {motion} from "framer-motion";
|
||||||
|
|
||||||
|
export function Nav() {
|
||||||
|
const [active, setActive] = useState(false);
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<nav className="header">
|
||||||
|
<MenuButton active={active} setActive={setActive}/>
|
||||||
|
<Title/>
|
||||||
|
</nav>
|
||||||
|
<Menu active={active}/>
|
||||||
|
<img className="wave" alt="wave" src={wave}/>
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function MenuButton(props : { active: boolean, setActive: (_:boolean) => void }) {
|
||||||
|
const {active, setActive} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="menu-btn click">
|
||||||
|
<button>
|
||||||
|
<FontAwesomeIcon icon={faBars} onClick={function() {
|
||||||
|
setActive(!active);
|
||||||
|
}} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Title() {
|
||||||
|
return (
|
||||||
|
<a href="/" className="name click">
|
||||||
|
<motion.h1>Tymur Arsentiev</motion.h1>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
src/nav/menu.scss
Normal file
16
src/nav/menu.scss
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
@import "./nav";
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: $menu;
|
||||||
|
z-index: 10;
|
||||||
|
color: white;
|
||||||
|
width: 25%;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
div {
|
||||||
|
padding: $padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/nav/nav.scss
Normal file
52
src/nav/nav.scss
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
$padding: 15px;
|
||||||
|
$menu: #282c34;
|
||||||
|
|
||||||
|
.click:hover {
|
||||||
|
opacity: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.click:active {
|
||||||
|
opacity: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-btn {
|
||||||
|
justify-self: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
button {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
position: absolute;
|
||||||
|
font-weight: bold;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background-color: $menu;
|
||||||
|
padding: $padding;
|
||||||
|
display: flex;
|
||||||
|
font-size: calc(10px + 2vmin);
|
||||||
|
color: white;
|
||||||
|
min-height: 3 * $padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
align-self: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.wave {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
left: -10%;
|
||||||
|
width: 110%;
|
||||||
|
}
|
||||||
14
src/router/RouterContext.tsx
Normal file
14
src/router/RouterContext.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import {createContext, PropsWithChildren, useContext, useSyncExternalStore} from "react";
|
||||||
|
|
||||||
|
const RouterContext = createContext<{}>({});
|
||||||
|
|
||||||
|
export function useRouter() {
|
||||||
|
return useContext(RouterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RouterProvider(props : PropsWithChildren) {
|
||||||
|
|
||||||
|
return <RouterContext.Provider value={{}}>
|
||||||
|
{props.children}
|
||||||
|
</RouterContext.Provider>
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user