From 82f2ed068168c4c05b50f85b47952cfb353d4968 Mon Sep 17 00:00:00 2001 From: Akshat Mittal Date: Wed, 6 Sep 2023 18:54:23 +0530 Subject: [PATCH] feat: completed navigation menu --- components/Navigation/index.tsx | 92 ++++++++++++++ components/Navigation/styles.module.scss | 148 +++++++++++++++++++++++ pages/events/[...slug].tsx | 2 + styles/config/_colors.scss | 3 +- styles/config/_variables.scss | 3 +- styles/pages/Event.module.scss | 16 +-- styles/pages/Home.module.scss | 2 +- 7 files changed, 255 insertions(+), 11 deletions(-) create mode 100644 components/Navigation/index.tsx create mode 100644 components/Navigation/styles.module.scss diff --git a/components/Navigation/index.tsx b/components/Navigation/index.tsx new file mode 100644 index 0000000..b3fdc64 --- /dev/null +++ b/components/Navigation/index.tsx @@ -0,0 +1,92 @@ +import React, { useEffect, useState } from "react"; +import { stylesConfig } from "@/utils/functions"; +import styles from "./styles.module.scss"; +import navLinks from "@/constants/navigation"; +import Link from "next/link"; + +interface NavigationProps extends React.HTMLAttributes { + theme?: "light" | "dark"; +} + +const classes = stylesConfig(styles, "navigation"); + +const Navigation: React.FC = ({ theme = "light" }) => { + const [isOpen, setIsOpen] = useState(false); + const [isClosing, setIsClosing] = useState(false); + + const midIndex = Math.floor(navLinks.length / 2) + 1; + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") { + setIsClosing(true); + setTimeout(() => { + setIsOpen(false); + setIsClosing(false); + }, 250); + } + }; + + if (isOpen) document.addEventListener("keydown", handleKeyDown); + else document.removeEventListener("keydown", handleKeyDown); + + return () => document.removeEventListener("keydown", handleKeyDown); + }, [isOpen]); + + return ( + <> + + {isOpen ? ( + + ) : null} + + ); +}; + +export default Navigation; diff --git a/components/Navigation/styles.module.scss b/components/Navigation/styles.module.scss new file mode 100644 index 0000000..013b11c --- /dev/null +++ b/components/Navigation/styles.module.scss @@ -0,0 +1,148 @@ +@import "@/styles/config/mixins"; +@import "@/styles/config/animations"; + +.navigation { + &-btn { + @include init-button; + position: fixed; + top: 56px; + right: 56px; + z-index: 100; + width: 48px; + height: 48px; + + span { + width: 48px; + height: 1px; + background-color: var(--color-white); + position: relative; + + &::before, + &::after { + content: ""; + position: absolute; + left: 0; + width: 100%; + height: 1px; + background-color: var(--color-white); + } + + &::before { + transform: translateY(-12px); + } + + &::after { + transform: translateY(12px); + } + } + + &--open { + span { + background-color: transparent; + + &::before { + transform: translateY(0.5px) rotate(45deg); + } + + &::after { + transform: translateY(-0.5px) rotate(-45deg); + } + } + } + } + + &-nav { + width: 100%; + height: 100vh; + position: fixed; + top: 0; + left: 0; + z-index: 99; + background-color: var(--theme-indigo); + transition: transform 0.3s ease-in-out; + display: flex; + justify-content: flex-start; + align-items: center; + padding: 96px; + animation: fade-bottom-in 0.4s ease-in-out; + + @include responsive(phone) { + padding: 48px; + flex-direction: column; + gap: 16px; + justify-content: center; + } + + &-left, + &-right { + width: 50%; + height: 100%; + display: flex; + justify-content: space-between; + align-items: center; + flex-direction: column; + gap: 16px; + padding: 0 5%; + + @include responsive(phone) { + width: 100%; + height: auto; + padding: 0 32px; + justify-content: center; + } + + a { + width: 100%; + @include font( + var(--font-red-hat-display), + 36px, + 400, + 150%, + var(--color-white) + ); + text-decoration: none; + position: relative; + + &::before { + content: attr(data-index); + position: absolute; + left: -80px; + top: 50%; + transform: translateY(-50%) rotate(-90deg); + font-size: 16px; + color: var(--color-white); + + @include responsive(phone) { + left: -40px; + } + } + + &::after { + content: ""; + position: absolute; + bottom: -4px; + left: 0; + width: 0; + height: 1px; + background-color: var(--theme-navy); + } + + &:hover, + &:focus, + &:active { + border: none; + outline: none; + color: var(--theme-navy); + + &::after { + width: 70%; + } + } + } + } + + &--closing { + animation: fade-bottom-out 0.4s ease-in-out; + } + } +} diff --git a/pages/events/[...slug].tsx b/pages/events/[...slug].tsx index f9e944f..a1de449 100644 --- a/pages/events/[...slug].tsx +++ b/pages/events/[...slug].tsx @@ -10,6 +10,7 @@ import useStore from "@/hooks/store"; import { getEvent } from "@/utils/api/events"; import { stylesConfig } from "@/utils/functions"; import styles from "@/styles/pages/Event.module.scss"; +import Navigation from "@/components/Navigation"; interface EventPageProps { event: IEvent; @@ -25,6 +26,7 @@ const EventPage: React.FC = ({ event }) => { if (!event) return null; return ( <> +