이전까지 props나 기본적인 JSX에 대한 사용법을 다루었다.
이번에는 이를 응용해서 네비게이션바를 만들어보려고한다.
디자인은 피그마로 하였다.
왼쪽에 네비게이션바가 위치하며, 상단부터 로고 / 프로필 / 메뉴바 / 푸터 로 나눌 수 있다.
푸터에는 라이트모드와 다크모드를 선택하고, 도움말을 받을수있는 버튼이 위치한다.
네비게이션바는 모든 페이지 내에 존재하므로 특정 페이지의 컴포넌트로 위치할 수 없다.
여기서 폴더 구조는 다음과 같다.
src/
ㄴ assets/
각종 아이콘들...
ㄴ pages/
ㄴ Home/
ㄴ components/
Home.js
ㄴ Calendar/
ㄴ components/
Calendar.js
ㄴ Mystudies/
ㄴ components/
Mystudies.js
ㄴ Settings/
ㄴ components/
Settings.js
ㄴ components/
ㄴ 각종 글로벌 컴포넌트들..
네비게이션바는 모든 페이지에 존재해야하는 컴포넌트이므로, 글로벌 컴포넌트라고 볼 수 있다.
그래서 pages 하위에 components 디렉토리를 만들어서 이쪽에서 Nav.js
로 관리하려고 한다.
필자는 부트스트랩, 세멘틱UI등 많은 CSS 도우미들이있지만, 바닐라 CSS와 Styled Components를 활용하여 디자인하였다.
import styled from "styled-components";
const StyledNav = styled.div`
display: flex;
flex-direction: column;
align-items: center;
width: 15rem;
height: 100vh;
background-color: #000000;
`;
const StyledLogo = styled.img`
margin: 0 auto 2rem auto;
width: 9rem;
padding-top: 2rem;
`;
const StyledProfile = styled.div`
display: flex;
flex-direction: column;
align-items: center;
padding: 4rem 0rem;
`;
const StyledProfileImage = styled.img`
width: 8rem;
height: 8rem;
border-radius: 50%;
margin-bottom: 1rem;
`;
const StyledProfileName = styled.div`
color: #dadada;
font-family: roboto;
font-size: 1rem;
font-weight: 500;
margin-bottom: 0.5rem;
`;
const StlyedProfileEmail = styled.div`
color: #dadada;
font-family: roboto;
font-size: 0.75rem;
font-weight: 500;
margin-bottom: 0.5rem;
`;
const StyledMenu = styled.div`
padding: 0rem 2rem;
display: flex;
flex-direction: column;
align-items: flex-start;
`;
const StyledMenuItem = styled.div`
display: flex;
flex-direction: row;
align-items: flex-start;
margin-bottom: 1.2rem;
`;
const StyledMenuItemIcon = styled.img`
width: 1.75rem;
height: 1.75rem;
margin-right: 0.5rem;
`;
const StyledMenuItemText = styled.div`
color: ${(props) => (props.isMenuSelected ? "#ffffff" : "#adb3be")};
font-family: roboto;
font-size: 1.25rem;
`;
const StyledMenuFooter = styled.div`
margin-top: auto;
margin-bottom: 2rem;
display: flex;
flex-direction: row;
align-items: space-between;
`;
const StyledDarkLightModeContainer = styled.div`
display: flex;
flex-direction: row;
align-items: center;
`;
const StyledDarkLightModeBackground = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 2rem;
height: 2rem;
border-radius: 50%;
margin-right: 0.5rem;
background-color: ${(props) =>
props.isModeSelected ? "#353B4B" : "transparent"};
`;
const StyledDarkLightMode = styled.img`
width: 1.5rem;
height: 1.5rem;
`;
const StyledHelp = styled.img`
margin-left: auto;
width: 2rem;
height: 2rem;
`;
function Nav({ imageUrl, name, email, selectedMenu, isDarkMode }) {
return (
<StyledNav>
<StyledLogo src={require("../../../assets/logo.png")} alt="logo" />
<StyledProfile>
<StyledProfileImage src={imageUrl} alt="profile" />
<StyledProfileName>{name}</StyledProfileName>
<StlyedProfileEmail>{email}</StlyedProfileEmail>
</StyledProfile>
<StyledMenu>
<StyledMenuItem>
<StyledMenuItemIcon
src={
selectedMenu == "home"
? require("../../../assets/home-select.png")
: require("../../../assets/home-unselect.png")
}
alt="home"
/>
<StyledMenuItemText isMenuSelected={selectedMenu == "home"}>
Home
</StyledMenuItemText>
</StyledMenuItem>
<StyledMenuItem>
<StyledMenuItemIcon
src={
selectedMenu == "calendar"
? require("../../../assets/calendar-select.png")
: require("../../../assets/calendar-unselect.png")
}
alt="home"
/>
<StyledMenuItemText isMenuSelected={selectedMenu == "calendar"}>
Calendar
</StyledMenuItemText>
</StyledMenuItem>
<StyledMenuItem>
<StyledMenuItemIcon
src={
selectedMenu == "mystudies"
? require("../../../assets/mystudies-select.png")
: require("../../../assets/mystudies-unselect.png")
}
alt="home"
/>
<StyledMenuItemText isMenuSelected={selectedMenu == "mystudies"}>
My Studies
</StyledMenuItemText>
</StyledMenuItem>
<StyledMenuItem>
<StyledMenuItemIcon
src={
selectedMenu == "settings"
? require("../../../assets/settings-select.png")
: require("../../../assets/settings-unselect.png")
}
alt="home"
/>
<StyledMenuItemText isMenuSelected={selectedMenu == "settings"}>
Settings
</StyledMenuItemText>
</StyledMenuItem>
</StyledMenu>
<StyledMenuFooter>
<StyledDarkLightModeContainer>
<StyledDarkLightModeBackground isModeSelected={isDarkMode == false}>
<StyledDarkLightMode
src={
isDarkMode
? require("../../../assets/light-unselect.png")
: require("../../../assets/light-select.png")
}
/>
</StyledDarkLightModeBackground>
<StyledDarkLightModeBackground isModeSelected={isDarkMode == true}>
<StyledDarkLightMode
src={
isDarkMode
? require("../../../assets/dark-select.png")
: require("../../../assets/dark-unselect.png")
}
/>
</StyledDarkLightModeBackground>
</StyledDarkLightModeContainer>
<StyledHelp src={require("../../../assets/help.png")} />
</StyledMenuFooter>
</StyledNav>
);
}
export default Nav;
컴포넌트는 함수형 컴포넌트로 선언하였으며, Styled Components는 함수의 밖, 글로벌 영역에 선언을 한다.
그리고 프로필사진 링크, 프로필이름, 프로필이메일, 어떤메뉴를 선택했는지를 선택할 수 있는 props들을 사용한다.
그래서 전역으로 프로필사진 링크, 프로필이름, 프로필이메일, 어떤메뉴를 선택했는지에 대한 값을
부모에게 전달받으면 네비게이션 바는 이를 받아 화면에서 출력할 수 있게 된다.