Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Design] Mobile ver. - Header 반응형 구현 #371

Merged
merged 25 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7f57cdd
init: 파일 생성
lydiacho Aug 6, 2024
0511324
fix: theme color 네이밍 범용적으로 수정
lydiacho Aug 6, 2024
9243911
move: Nav 디렉토리 만들어서 컴포넌트 분리
lydiacho Aug 6, 2024
8499b99
feat: react-responsive 설치 및 useDevice hook 추가
lydiacho Aug 6, 2024
5dd0d93
feat: isTablet, isMobile 공용 useDevice 추가
lydiacho Aug 6, 2024
81cccb1
fix: Logo svg className prop 확장
lydiacho Aug 6, 2024
6af78f6
chore: PC지원 막기 임시 해제
lydiacho Aug 6, 2024
103d010
design: tab/mob ver. 헤더 로고, 햄버거 조건부 렌더링
lydiacho Aug 6, 2024
6b9d655
design: 햄버거 토클 시 background 변경
lydiacho Aug 6, 2024
991774c
Merge branch 'develop' of https://github.com/sopt-makers/sopt-recruit…
lydiacho Aug 7, 2024
1f9bafa
fix: TextBox이메일 width 처리 누락 해결
lydiacho Aug 7, 2024
d25f739
fix: 달라진 useDevice 반환값에 따른 수정
lydiacho Aug 7, 2024
f6d8b81
fix: header position fixed로 수정 및 layout marginTop 추가
lydiacho Aug 7, 2024
0abb01a
design: header padding 반응형
lydiacho Aug 7, 2024
3670e36
fix: 디자인 변경사항 (padding값) 반영
lydiacho Aug 7, 2024
07936d0
feat: Nav 내부의 MenuList 컴포넌트 분리
lydiacho Aug 7, 2024
31d271e
design: 드롬메뉴 헤더 반응형
lydiacho Aug 7, 2024
83a0595
feat: DEVICE_TYPE에 따라 isMenuOpen값 초기화
lydiacho Aug 7, 2024
ae771ba
feat: 햄버거 버튼과 닫기 버튼
lydiacho Aug 8, 2024
1b85135
design: dimmed 배경
lydiacho Aug 8, 2024
7dcc466
feat: dimmed 배경 클릭 시 헤더 닫히도록
lydiacho Aug 10, 2024
dc6f1b9
design: 반응형 header 드롭메뉴 애니메이션
lydiacho Aug 10, 2024
c167161
design: 반응형 header active 페이지 bolder 추가
lydiacho Aug 10, 2024
aaea71f
design: 햄버거버튼 다크모드 조건부스타일링
lydiacho Aug 10, 2024
c1bba63
feat: 애니메이션 keyframes 공통 animationa.css.ts로 분리
lydiacho Aug 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/common/assets/MakersDarkLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const MakersDarkLogo = () => {
const MakersDarkLogo = ({ className }: { className?: string }) => {
return (
<svg width="87" height="31" viewBox="0 0 87 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="87"
height="31"
viewBox="0 0 87 31"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}>
<g clipPath="url(#clip0_2501_966)">
<path
fillRule="evenodd"
Expand Down
10 changes: 8 additions & 2 deletions src/common/assets/MakersLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const MakersLogo = () => {
const MakersLogo = ({ className }: { className?: string }) => {
return (
<svg width="87" height="30" viewBox="0 0 87 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="87"
height="30"
viewBox="0 0 87 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}>
<g clipPath="url(#clip0_2311_4700)">
<path
fillRule="evenodd"
Expand Down
10 changes: 8 additions & 2 deletions src/common/assets/NowsoptLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const NowsoptLogo = () => {
const NowsoptLogo = ({ className }: { className?: string }) => {
return (
<svg width="87" height="30" viewBox="0 0 87 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width="87"
height="30"
viewBox="0 0 87 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}>
<g id="Frame" clipPath="url(#clip0_1535_12708)">
<g id="Group">
<path
Expand Down
7 changes: 5 additions & 2 deletions src/common/components/Input/components/InputTheme/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ export const TextBox이메일 = ({
return (
<TextBox label="이메일" name="email" required>
<InputLine
style={{ width: 308, paddingRight: isActive ? 50 : 16 }}
style={{
width: DEVICE_TYPE === 'DESK' ? 308 : DEVICE_TYPE === 'TAB' ? 246 : 208,
paddingRight: isActive ? 50 : 16,
}}
name="email"
placeholder="이메일을 입력해주세요."
type="email"
Expand All @@ -158,7 +161,7 @@ export const TextBox이메일 = ({
<Timer isActive={isActive} onResetTimer={handleResetTimer} />
</InputLine>
<InputLine
style={{ width: 308 }}
style={{ width: DEVICE_TYPE === 'DESK' ? 308 : DEVICE_TYPE === 'TAB' ? 246 : 208 }}
id="verification-code"
readOnly={!isActive}
name="code"
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { track } from '@amplitude/analytics-browser';
import { NavLink } from 'react-router-dom';

import { menuItem, menuLink } from './style.css';
import { useDevice } from '@hooks/useDevice';

import { menuItemVar, menuLinkVar } from './style.css';

interface MenuItemProps {
text: string;
Expand All @@ -13,18 +15,20 @@ interface MenuItemProps {
}

const MenuItem = ({ text, path, target, amplitudeId, className, onClick }: MenuItemProps) => {
const DEVICE_TYPE = useDevice();

return (
<li className={`${className} ${menuItem}`}>
<li className={`${className} ${menuItemVar[DEVICE_TYPE]}`}>
{path ? (
<NavLink
to={path}
className={menuLink}
className={menuLinkVar[DEVICE_TYPE]}
onClick={() => (amplitudeId ? track(amplitudeId) : null)}
target={target}>
{text}
</NavLink>
) : (
<p className={`${onClick ? menuLink : null}`} onClick={onClick}>
<p className={`${onClick ? menuLinkVar[DEVICE_TYPE] : null}`} onClick={onClick}>
{text}
</p>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { style, styleVariants } from '@vanilla-extract/css';

import { theme } from 'styles/theme.css';

const menuItem = style({
...theme.font.HEADING_6_18_B,
});

export const menuItemVar = styleVariants({
DESK: [
menuItem,
{
color: theme.color.baseText,
},
],
TAB: [
menuItem,
{
color: theme.color.grayButtonFill,
},
],
MOB: [
menuItem,
{
color: theme.color.grayButtonFill,
},
],
});

const menuLink = style({
textDecoration: `underline transparent 2px`,
textUnderlineOffset: 21,
transition: 'all 0.2s ease-out',
cursor: 'pointer',
});

export const menuLinkVar = styleVariants(
{
DESK: {
hover: {
textDecorationColor: theme.color.primary,
},
active: {
color: theme.color.primary,
},
},
TAB: {
hover: {
color: theme.color.whiteButtonFill,
},
active: {
color: theme.color.whiteButtonFill,
fontWeight: 'bolder',
},
},
MOB: {
hover: {
color: theme.color.whiteButtonFill,
},
active: {
color: theme.color.whiteButtonFill,
fontWeight: 'bolder',
},
},
},
({ hover, active }) => [
menuLink,
{
selectors: {
'&:hover:not([disabled])': hover,
'&.active': active,
},
},
],
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { reset, track } from '@amplitude/analytics-browser';
import { useContext, useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import { useDevice } from '@hooks/useDevice';
import { RecruitingInfoContext } from '@store/recruitingInfoContext';

import { dimmedBgVar, menuContainerVar, menuList, menuMobListVar } from './style.css';
import { MENU_ITEMS, MENU_ITEMS_MAKERS } from '../../contants';
import MenuItem from '../MenuItem';

const MenuList = ({ isMenuOpen, onClickMenuToggle }: { isMenuOpen?: boolean; onClickMenuToggle?: () => void }) => {
const DEVICE_TYPE = useDevice();
const navigate = useNavigate();
const { pathname } = useLocation();
const [isShown, setIsShown] = useState(isMenuOpen);
const [animation, setAnimation] = useState<'open' | 'close'>(isMenuOpen ? 'open' : 'close');

useEffect(() => {
if (isMenuOpen) {
setIsShown(true);
setAnimation('open');
} else {
setAnimation('close');
const timer = setTimeout(() => setIsShown(false), 300);
return () => clearTimeout(timer);
}
}, [isMenuOpen]);

const isSignedIn = localStorage.getItem('soptApplyAccessToken');

const {
recruitingInfo: { name, isMakers },
} = useContext(RecruitingInfoContext);
const menuItems = isMakers ? MENU_ITEMS_MAKERS : MENU_ITEMS;
const handleLogout = () => {
track('click-gnb-logout');
reset();
localStorage.removeItem('soptApplyAccessToken');
localStorage.removeItem('soptApplyAccessTokenExpiredTime');
pathname === '/' ? window.location.reload() : navigate('/');
};

if (onClickMenuToggle && !isShown) return null;

return (
<nav>
<ul
className={DEVICE_TYPE !== 'DESK' ? `${menuMobListVar[DEVICE_TYPE]} ${menuContainerVar[animation]}` : menuList}>
{!isSignedIn && (
<>
{menuItems.map(({ text, path, target, amplitudeId }) => (
<MenuItem key={text} text={text} path={path} target={target} amplitudeId={amplitudeId} />
))}
<MenuItem key="로그인" text="로그인" path="/" amplitudeId="click-gnb-signin" />
</>
)}
{isSignedIn && name && (
<>
{menuItems.map(({ text, path, target, amplitudeId }) => (
<MenuItem key={text} text={text} path={path} target={target} amplitudeId={amplitudeId} />
))}
<MenuItem key="로그아웃" text="로그아웃" onClick={handleLogout} />
<MenuItem key="로그인완료" text={`${name}님`} className="amp-block" />
</>
)}
</ul>
{onClickMenuToggle && isShown && <div className={dimmedBgVar[animation]} onClick={onClickMenuToggle} />}
</nav>
);
};

export default MenuList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { style, styleVariants } from '@vanilla-extract/css';

import { Z_INDEX } from '@constants/zIndex';
import { fadeIn, fadeInDown, fadeOut, fadeOutUp } from 'styles/animation.css';
import { theme } from 'styles/theme.css';

export const menuContainerVar = styleVariants({
open: {
animation: `${fadeInDown} 0.3s`,
},
close: {
animation: `${fadeOutUp} 0.3s`,
animationFillMode: 'forwards',
},
});
export const menuList = style({
display: 'flex',
alignItems: 'center',
gap: 40,
});

const menuMobList = style({
display: 'flex',
flexDirection: 'column',
gap: 18,
position: 'fixed',
top: 0,
left: 0,
width: '100%',
backgroundColor: theme.color.blackBackground,
zIndex: Z_INDEX.gnbMenu,
});

export const menuMobListVar = styleVariants({
TAB: [
menuMobList,
{
padding: '92px 40px 40px 40px',
},
],
MOB: [
menuMobList,
{
padding: '86px 20px 36px 20px',
},
],
});

export const dimmedBg = style({
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100dvh',
backgroundColor: theme.color.backgroundDimmed,
zIndex: Z_INDEX.gnbBg,

cursor: 'pointer',
});

export const dimmedBgVar = styleVariants({
open: [
dimmedBg,
{
animation: `${fadeIn} 0.3s`,
},
],
close: [
dimmedBg,
{
animation: `${fadeOut} 0.3s`,
animationFillMode: 'forwards',
},
],
});
24 changes: 24 additions & 0 deletions src/common/components/Layout/components/Header/Nav/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IconMenu, IconXClose } from '@sopt-makers/icons';
import { useContext } from 'react';

import { useDevice } from '@hooks/useDevice';
import { ThemeContext } from '@store/themeContext';
import { theme } from 'styles/theme.css';

import MenuList from './MenuList';
import { menuIconVar } from './style.css';

const Nav = ({ isMenuOpen, onClickMenuToggle }: { isMenuOpen: boolean; onClickMenuToggle: () => void }) => {
const DEVICE_TYPE = useDevice();
const { isLight } = useContext(ThemeContext);

return DEVICE_TYPE !== 'DESK' ? (
<i className={menuIconVar[DEVICE_TYPE]} onClick={onClickMenuToggle}>
{isMenuOpen ? <IconXClose /> : <IconMenu color={isLight ? 'currentColor' : theme.color.white} />}
</i>
) : (
<MenuList />
);
};

export default Nav;
Loading