From 3f964610d6d4e2240a6666133df123bc640c659b Mon Sep 17 00:00:00 2001 From: "sumi.byun" Date: Sat, 23 Sep 2023 21:28:16 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]=20Mobile=20Nav=20Menu=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Journey section add * feat: 여정 합류 PC * feat: layout media query add * feat: journey mobile * feat: 모집안내 바로가기 생성 * refactor: css 분리 * fix: build error fix * feat: schedule 상수로 분리, main 에 추가 * style: 14기 일정 추가 * style: SectionTitle 반응형 추가 * feat: faq main component 추가 * feat: main sign image 추가 * fix: optional desc 적용 * fix: 설명 있을때만 돔 생성 * refactor: main에만 종속되어있는 컴포넌트 구조 변경 * feat: 14기 지원 버튼 추가 (메인 마지막) * style: gnb pc design 수정 * feat: mobile menu icon 추가 * refactor: pc footer theme 적용 * style: footer 모바일 반응형 추가 * feat: mobile menu icon 추가 * feat: mobile nav 추가 * [Style] GNB, Footer 반응형 작업 (#283) * style: gnb pc design 수정 * feat: mobile menu icon 추가 * refactor: pc footer theme 적용 * style: footer 모바일 반응형 추가 --------- Co-authored-by: byun sumi * fix: merge error fix * fix: merge error fix --------- Co-authored-by: byun sumi --- src/components/GNB/GNB.tsx | 56 ++++++++++---- src/components/GNB/MobileMenu.tsx | 62 ++++++++++++++++ src/components/GNB/MobileMenuIcon.tsx | 101 ++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 src/components/GNB/MobileMenu.tsx create mode 100644 src/components/GNB/MobileMenuIcon.tsx diff --git a/src/components/GNB/GNB.tsx b/src/components/GNB/GNB.tsx index 749c6cf2..255cc59d 100644 --- a/src/components/GNB/GNB.tsx +++ b/src/components/GNB/GNB.tsx @@ -1,12 +1,14 @@ +import { useState } from 'react'; import Image from 'next/image'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { css, Theme } from '@emotion/react'; +import { AnimatePresence } from 'framer-motion'; import { Button } from '~/components/Button'; -import { MenuIcon } from '~/components/Icons'; +import { MobileMenu } from '~/components/GNB/MobileMenu'; +import { MobileMenuIcon } from '~/components/GNB/MobileMenuIcon'; import { GNB_MENU_NAME, GNBMenu } from '~/constant/gnb'; -import { colors } from '~/styles/colors'; import { mediaQuery } from '~/styles/media'; const LOGO_IMAGE = `/images/logo.png`; @@ -23,12 +25,14 @@ function ApplyButton({ menu }: { menu: GNBMenu }) { export function GNB() { const { pathname } = useRouter(); + const [isMenuOpen, setIsMenuOpen] = useState(false); const getActiveLinkcss = (menu: GNBMenu) => { if (pathname.startsWith(menu.href)) { return activeLinkCss; } return inActiveLinkCss; }; + return ( <> +
); } -const navCss = css` - background-color: ${colors.black800}; +const navCommonCss = (theme: Theme) => css` + background-color: ${theme.colors.black800}; position: fixed; - padding: 20px 32px; top: 0; left: 0; z-index: 9998; width: 100vw; `; +const navCss = (theme: Theme) => css` + ${navCommonCss(theme)}; + padding: 20px 32px; + + ${mediaQuery('mobile')} { + display: none; + } +`; + const blankCss = css` width: 100vw; height: 82px; + + ${mediaQuery('mobile')} { + height: 72px; + } `; const navWrapperCss = css` @@ -85,13 +107,9 @@ const navWrapperCss = css` const menuContainerCss = css` display: flex; gap: 32px; - - ${mediaQuery('mobile')} { - display: none; - } `; -const mobileMenuContainerCss = css` +const mobileNavCss = css` display: none; ${mediaQuery('mobile')} { @@ -114,3 +132,15 @@ const inActiveLinkCss = (theme: Theme) => css` const linkCss = (theme: Theme) => css` ${theme.typos.pretendard.body1}; `; + +const mobileMenuGNBCss = (theme: Theme) => css` + ${navCommonCss(theme)}; + padding: 20px 32px; + display: flex; + align-items: center; + justify-content: space-between; + + & > a { + margin-top: 6px; + } +`; diff --git a/src/components/GNB/MobileMenu.tsx b/src/components/GNB/MobileMenu.tsx new file mode 100644 index 00000000..e217c691 --- /dev/null +++ b/src/components/GNB/MobileMenu.tsx @@ -0,0 +1,62 @@ +import Link from 'next/link'; +import { css, Theme } from '@emotion/react'; +import { m } from 'framer-motion'; + +import { GNB_MENU_NAME } from '~/constant/gnb'; + +export function MobileMenu({}) { + return ( + +
    + {GNB_MENU_NAME.map(menu => ( +
  • + {menu.type === 'button' ? ( + + {menu.name} + + ) : ( + + {menu.name} + + )} +
  • + ))} +
+
+ ); +} + +const mobileMenuCss = (theme: Theme) => css` + z-index: 9997; + + width: 100vw; + height: fit-content; + position: fixed; + top: 0; + left: 0; + margin: auto; + background-color: ${theme.colors.black800}; + padding-top: 72px; + + overflow: hidden; + li { + padding: 12px 32px; + } +`; + +const activeLinkCss = (theme: Theme) => css` + color: ${theme.colors.yellow500}; +`; + +const inActiveLinkCss = (theme: Theme) => css` + color: ${theme.colors.white}; +`; + +const linkCss = (theme: Theme) => css` + ${theme.typos.pretendard.body1}; +`; diff --git a/src/components/GNB/MobileMenuIcon.tsx b/src/components/GNB/MobileMenuIcon.tsx new file mode 100644 index 00000000..5983146c --- /dev/null +++ b/src/components/GNB/MobileMenuIcon.tsx @@ -0,0 +1,101 @@ +import { css } from '@emotion/react'; + +interface Props { + onClick?: () => void; + isChecked?: boolean; +} +export function MobileMenuIcon({ onClick, isChecked }: Props) { + return ( +
+ + +
+ ); +} + +const containerCss = css` + position: relative; + width: 32px; + height: 32px; + + .menu { + position: absolute; + top: 0; + right: 0; + height: 100%; + max-width: 0; + min-width: 100px; + transition: 0.5s ease; + z-index: 1; + background-color: #eee; + } + + .burger-icon { + cursor: pointer; + display: inline-block; + position: absolute; + z-index: 2; + padding: 8px 0; + top: 8px; + right: 4px; + user-select: none; + width: auto; + + .burger-sticks { + background: #d9d9d9; + display: block; + height: 3px; + position: relative; + transition: background 0.2s ease-out; + width: 24px; + + &:before, + &:after { + background: #d9d9d9; + content: ''; + display: block; + height: 100%; + position: absolute; + transition: all 0.2s ease-out; + width: 100%; + } + + &:before { + top: 8px; + } + + &:after { + top: -8px; + } + } + } + + .burger-check { + display: none; + } + + .burger-check:checked ~ .burger-icon .burger-sticks { + background: transparent; + &:before { + transform: rotate(-45deg); + } + &:after { + transform: rotate(45deg); + } + } + + .burger-check:checked ~ .burger-icon:not(.steps) .burger-sticks { + &:before, + &:after { + top: 0; + } + } +`;