diff --git a/src/Router.tsx b/src/Router.tsx index 94daba7b..dde1771e 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -5,6 +5,7 @@ import HealthTest from './HealthTest'; import LecueNotePage from './LecueNote/page/LeceuNotePage'; import Login from './Login/page'; import Register from './Register/page'; +import SelectBookPage from './SelectBook/page/SelectBookPage'; import SplashPage from './Splash/page/SplashPage'; import StickerPack from './StickerPack/page/StickerPack'; import TargetPage from './Target/page/TargetPage'; @@ -21,6 +22,7 @@ function Router() { } /> } /> } /> + } /> ); diff --git a/src/SelectBook/components/BookTypeBox/BookTypeBox.style.ts b/src/SelectBook/components/BookTypeBox/BookTypeBox.style.ts new file mode 100644 index 00000000..19012005 --- /dev/null +++ b/src/SelectBook/components/BookTypeBox/BookTypeBox.style.ts @@ -0,0 +1,104 @@ +import styled from '@emotion/styled'; + +export const BookTypeBoxWrapper = styled.div<{ + bookType: number; + selectedBox: number; + isClickedSelectButton: boolean; +}>` + display: flex; + align-items: center; + flex-direction: column; + position: absolute; + + width: ${({ bookType, isClickedSelectButton }) => + bookType === 2 && isClickedSelectButton ? '28.4rem' : '16.5rem'}; + height: 34.9rem; + + border: ${({ bookType, selectedBox, theme }) => + selectedBox === 0 + ? `0.1rem solid ${theme.colors.LG}` + : selectedBox === bookType + ? `0.1rem solid ${theme.colors.key}` + : `0.1rem solid ${theme.colors.MG}`}; + border-radius: 0.4rem; + background-color: ${({ bookType, selectedBox, theme }) => + bookType === 2 && bookType === selectedBox + ? theme.colors.BG + : theme.colors.white}; + + transition: + width 0.5s ease, + transform 0.5s ease; + opacity: ${({ bookType, selectedBox }) => + selectedBox !== 0 && bookType !== selectedBox ? 0.5 : 1}; + + ${({ bookType }) => (bookType === 1 ? 'left' : 'right')}: 0; +`; + +export const BookTypeBoxTitle = styled.p<{ + bookType: number; + selectedBox: number; + isClickedSelectButton: boolean; +}>` + display: flex; + align-items: center; + + height: 3.7rem; + margin-top: 2.5rem; + margin-bottom: ${({ bookType, isClickedSelectButton }) => + bookType === 2 && isClickedSelectButton ? '0.7rem' : '2.7rem'}; + + color: ${({ bookType, selectedBox, theme }) => + bookType === 2 && bookType === selectedBox + ? theme.colors.white + : theme.colors.BG}; + ${({ theme, bookType, isClickedSelectButton }) => + bookType === 2 && isClickedSelectButton + ? theme.fonts.Head1_B_20 + : theme.fonts.Title1_SB_16}; +`; + +export const BookTypeBoxPrice = styled.p<{ + bookType: number; + selectedBox: number; +}>` + margin-top: 0.9rem; + + color: ${({ bookType, selectedBox, theme }) => + bookType === 2 && bookType === selectedBox + ? theme.colors.key + : theme.colors.BG}; + ${({ theme }) => theme.fonts.Head1_B_20}; +`; + +export const BookTypeBoxPriceWrapper = styled.div` + display: flex; + align-items: flex-end; + + column-gap: 0.7rem; +`; + +export const OneBookText = styled.p` + padding-bottom: 0.2rem; + + color: ${({ theme }) => theme.colors.MG}; + ${({ theme }) => theme.fonts.Body2_M_14}; +`; + +export const BookTypeBoxOptionList = styled.div<{ + bookType: number; + selectedBox: number; + isClickedSelectButton: boolean; +}>` + display: flex; + flex-direction: column; + row-gap: 0.6rem; + + margin-top: ${({ bookType, isClickedSelectButton }) => + bookType === 2 && isClickedSelectButton ? '1.5rem' : '3.85rem'}; + + color: ${({ bookType, selectedBox, theme }) => + bookType === 2 && bookType === selectedBox + ? theme.colors.white + : theme.colors.DG}; +`; diff --git a/src/SelectBook/components/BookTypeBox/index.tsx b/src/SelectBook/components/BookTypeBox/index.tsx new file mode 100644 index 00000000..ab96de59 --- /dev/null +++ b/src/SelectBook/components/BookTypeBox/index.tsx @@ -0,0 +1,78 @@ +import { ReactNode } from 'react'; + +import { ImgBookOrangeBig, ImgSaleprice } from '../../../assets'; +import BookTypeBoxOption from '../BookTypeBoxOption'; +import * as S from './BookTypeBox.style'; + +interface BookTypeBoxProps { + handleClickBookTypeBox: () => void; + selectedBox: number; + bookType: number; + bookTypeBoxTitle: string; + bookTypeBoxImg: ReactNode; + bookTypeBoxPrice: number; + isClickedSelectButton: boolean; + bookTypeBoxOptionList: string[]; +} + +function BookTypeBox({ + handleClickBookTypeBox, + bookType, + bookTypeBoxTitle, + bookTypeBoxImg, + bookTypeBoxPrice, + selectedBox, + isClickedSelectButton, + bookTypeBoxOptionList, +}: BookTypeBoxProps) { + return ( + { + if (isClickedSelectButton === false) { + handleClickBookTypeBox(); + } + }} + bookType={bookType} + selectedBox={selectedBox} + isClickedSelectButton={isClickedSelectButton} + > + + {bookTypeBoxTitle} + + {bookType === 2 && isClickedSelectButton ? ( + + ) : ( + bookTypeBoxImg + )} + + {bookType === 2 && isClickedSelectButton && } + + + {bookType === 2 && isClickedSelectButton + ? '0원' + : `${bookTypeBoxPrice}원`} + + {bookType === 2 && !isClickedSelectButton ? ( + /1권 + ) : ( + <> + )} + + + {bookTypeBoxOptionList.map((option, idx) => ( + + ))} + + + ); +} + +export default BookTypeBox; diff --git a/src/SelectBook/components/BookTypeBoxOption/BookTypeBoxOption.style.ts b/src/SelectBook/components/BookTypeBoxOption/BookTypeBoxOption.style.ts new file mode 100644 index 00000000..a6856627 --- /dev/null +++ b/src/SelectBook/components/BookTypeBoxOption/BookTypeBoxOption.style.ts @@ -0,0 +1,12 @@ +import styled from '@emotion/styled'; + +export const BookTypeBoxOptionWrapper = styled.div` + display: flex; + column-gap: 0.5rem; + + align-items: center; +`; + +export const BookTypeBoxOptionText = styled.p` + ${({ theme }) => theme.fonts.Body2_M_14}; +`; diff --git a/src/SelectBook/components/BookTypeBoxOption/index.tsx b/src/SelectBook/components/BookTypeBoxOption/index.tsx new file mode 100644 index 00000000..a4a2b200 --- /dev/null +++ b/src/SelectBook/components/BookTypeBoxOption/index.tsx @@ -0,0 +1,17 @@ +import { IcCheck } from '../../../assets'; +import * as S from './BookTypeBoxOption.style'; + +interface BookTypeBoxOptionProps { + bookTypeBoxOption: string; +} + +function BookTypeBoxOption({ bookTypeBoxOption }: BookTypeBoxOptionProps) { + return ( + + + {bookTypeBoxOption} + + ); +} + +export default BookTypeBoxOption; diff --git a/src/SelectBook/components/CompleteButton/CompleteButton.style.ts b/src/SelectBook/components/CompleteButton/CompleteButton.style.ts new file mode 100644 index 00000000..7f21332d --- /dev/null +++ b/src/SelectBook/components/CompleteButton/CompleteButton.style.ts @@ -0,0 +1,6 @@ +import styled from '@emotion/styled'; + +export const CompleteButtonWrapper = styled.div` + width: 100%; + margin-bottom: 2rem; +`; diff --git a/src/SelectBook/components/CompleteButton/index.tsx b/src/SelectBook/components/CompleteButton/index.tsx new file mode 100644 index 00000000..92d21efd --- /dev/null +++ b/src/SelectBook/components/CompleteButton/index.tsx @@ -0,0 +1,19 @@ +import Button from '../../../components/common/Button'; +import * as S from './CompleteButton.style'; + +interface CompleteButtonProps { + isActive: boolean; + onClick: () => void; +} + +function CompleteButton({ isActive, onClick }: CompleteButtonProps) { + return ( + + + + ); +} + +export default CompleteButton; diff --git a/src/SelectBook/components/MakeLecueBookButton/MakeLecueBookButton.style.ts b/src/SelectBook/components/MakeLecueBookButton/MakeLecueBookButton.style.ts new file mode 100644 index 00000000..cf99d31c --- /dev/null +++ b/src/SelectBook/components/MakeLecueBookButton/MakeLecueBookButton.style.ts @@ -0,0 +1,6 @@ +import styled from '@emotion/styled'; + +export const MakeLecueBookButtonWrapper = styled.div` + width: 100%; + margin-bottom: 2rem; +`; diff --git a/src/SelectBook/components/MakeLecueBookButton/index.tsx b/src/SelectBook/components/MakeLecueBookButton/index.tsx new file mode 100644 index 00000000..bd50a34d --- /dev/null +++ b/src/SelectBook/components/MakeLecueBookButton/index.tsx @@ -0,0 +1,19 @@ +import Button from '../../../components/common/Button'; +import * as S from './MakeLecueBookButton.style'; + +interface MakeLecueBookButtonProps { + isActive: boolean; + onClick: () => void; +} + +function MakeLecueBookButton({ isActive, onClick }: MakeLecueBookButtonProps) { + return ( + + + + ); +} + +export default MakeLecueBookButton; diff --git a/src/SelectBook/constants/.gitkeep b/src/SelectBook/constants/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/SelectBook/hooks/.gitkeep b/src/SelectBook/hooks/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/SelectBook/page/SelectBookPage/SelectBookPage.style.ts b/src/SelectBook/page/SelectBookPage/SelectBookPage.style.ts new file mode 100644 index 00000000..15778218 --- /dev/null +++ b/src/SelectBook/page/SelectBookPage/SelectBookPage.style.ts @@ -0,0 +1,69 @@ +import styled from '@emotion/styled'; + +import { ImgEvent } from '../../../assets'; + +export const SelectBookPageWrapper = styled.div` + display: flex; + align-items: center; + flex-direction: column; + + width: 100vw; + height: 100dvh; +`; + +export const SelectBookPageBodyWrapper = styled.div` + display: flex; + justify-content: space-between; + flex-direction: column; + + width: 100%; + height: calc(100vh - 5.4rem); + padding: 0 1.6rem; + margin-top: 5.4rem; +`; + +export const SelectBookContainer = styled.div<{ + isClickedSelectButton: boolean; +}>` + width: 100%; + margin-top: ${({ isClickedSelectButton }) => + isClickedSelectButton ? '3.6rem' : '5.4rem'}; +`; + +export const SectionTitle = styled.p` + color: ${({ theme }) => theme.colors.BG}; + ${({ theme }) => theme.fonts.Head2_SB_18}; +`; + +export const SectionOrangeTitle = styled.p` + color: ${({ theme }) => theme.colors.key}; + ${({ theme }) => theme.fonts.Head2_SB_18}; +`; + +export const BookTypeContainerWrapper = styled.div<{ + isClickedSelectButton: boolean; +}>` + display: flex; + justify-content: center; + + width: 100%; + margin-top: ${({ isClickedSelectButton }) => + isClickedSelectButton ? '3.3rem' : '4rem'}; +`; + +export const BookTypeContainer = styled.div` + display: flex; + justify-content: space-between; + position: relative; + + width: 34.3rem; +`; + +export const StyledImgEvent = styled(ImgEvent)` + position: absolute; + top: -3.5rem; + right: 1.1rem; + z-index: 5; + + transition: width 0.5s ease; +`; diff --git a/src/SelectBook/page/SelectBookPage/index.tsx b/src/SelectBook/page/SelectBookPage/index.tsx new file mode 100644 index 00000000..be8e5f4b --- /dev/null +++ b/src/SelectBook/page/SelectBookPage/index.tsx @@ -0,0 +1,91 @@ +import { useState } from 'react'; + +import { ImgBookBackgray, ImgBookOrange } from '../../../assets'; +import Header from '../../../components/common/Header'; +import BookTypeBox from '../../components/BookTypeBox'; +import CompleteButton from '../../components/CompleteButton'; +import MakeLecueBookButton from '../../components/MakeLecueBookButton'; +import * as S from './SelectBookPage.style'; + +const basicLecueBookOptions = ['레큐노트 최대 100장', '텍스트 & 배경색 2종']; +const premiumLecueBookOptions = [ + '레큐노트 무제한', + '레큐노트 배경색 6종', + '스티커 꾸미기', +]; + +function SelectBookPage() { + const [selectedBox, setSelectedBox] = useState(0); + const [isClickedSelectButton, setIsClickedSelectButton] = useState(false); + + const handleClickCompleteButton = () => { + setIsClickedSelectButton(true); + setSelectedBox(2); + }; + + const handleClickMakeLecueBookButton = () => { + // API 쏘기... + }; + + return ( + +
+ + + {isClickedSelectButton ? ( + + 레큐는 이벤트 중! + 무료로 프리미엄 레큐북을 만들어요! + + ) : ( + 레큐북 타입 선택 + )} + + + {isClickedSelectButton && } + + setSelectedBox(selectedBox === 1 ? 0 : 1) + } + bookType={1} + bookTypeBoxTitle="베이직 레큐북" + bookTypeBoxImg={} + bookTypeBoxPrice={0} + selectedBox={selectedBox} + isClickedSelectButton={isClickedSelectButton} + bookTypeBoxOptionList={basicLecueBookOptions} + /> + + setSelectedBox(selectedBox === 2 ? 0 : 2) + } + bookType={2} + bookTypeBoxTitle="프리미엄 레큐북" + bookTypeBoxImg={} + bookTypeBoxPrice={990} + selectedBox={selectedBox} + isClickedSelectButton={isClickedSelectButton} + bookTypeBoxOptionList={premiumLecueBookOptions} + /> + + + + {isClickedSelectButton ? ( + + ) : ( + + )} + + + ); +} + +export default SelectBookPage; diff --git a/src/assets/icon/ic_check.svg b/src/assets/icon/ic_check.svg new file mode 100644 index 00000000..a3ed8914 --- /dev/null +++ b/src/assets/icon/ic_check.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/img_book_backgray.svg b/src/assets/img/img_book_backgray.svg new file mode 100644 index 00000000..d82a5411 --- /dev/null +++ b/src/assets/img/img_book_backgray.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/img/img_book_orange.svg b/src/assets/img/img_book_orange.svg new file mode 100644 index 00000000..47a21ab1 --- /dev/null +++ b/src/assets/img/img_book_orange.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/img/img_book_orange_big.svg b/src/assets/img/img_book_orange_big.svg new file mode 100644 index 00000000..d6846b0d --- /dev/null +++ b/src/assets/img/img_book_orange_big.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assets/img/img_event.svg b/src/assets/img/img_event.svg new file mode 100644 index 00000000..ca64c4dd --- /dev/null +++ b/src/assets/img/img_event.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/img/img_saleprice.svg b/src/assets/img/img_saleprice.svg new file mode 100644 index 00000000..2c08d30d --- /dev/null +++ b/src/assets/img/img_saleprice.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/index.ts b/src/assets/index.ts index 21e013ed..788fb95c 100644 --- a/src/assets/index.ts +++ b/src/assets/index.ts @@ -9,6 +9,7 @@ import BtnKakaologin from './button/btn_kakaologin.svg?react'; import IcArrowLeftBlack from './icon/ic_arrow_left_black.svg?react'; import IcArrowLeftWhite from './icon/ic_arrow_left_white.svg?react'; import IcCamera from './icon/ic_camera.svg?react'; +import IcCheck from './icon/ic_check.svg?react'; import IcCrown from './icon/ic_crown.svg?react'; import IcDate from './icon/ic_date.svg?react'; import IcHome from './icon/ic_home.svg?react'; @@ -16,6 +17,10 @@ import IcNotice from './icon/ic_notice.svg?react'; import IcSharing from './icon/ic_sharing.svg?react'; import IcX from './icon/ic_x.svg?react'; import ImgBook from './img/img_book.svg?react'; +import ImgBookBackgray from './img/img_book_backgray.svg?react'; +import ImgBookOrange from './img/img_book_orange.svg?react'; +import ImgBookOrangeBig from './img/img_book_orange_big.svg?react'; +import ImgEvent from './img/img_event.svg?react'; import ImgKakao01 from './img/img_kakao_01.svg?react'; import ImgKakao02 from './img/img_kakao_02.svg?react'; import ImgKakao03 from './img/img_kakao_03.svg?react'; @@ -27,6 +32,7 @@ import ImgKakaoStarWhite from './img/img_kakao_star_white.svg?react'; import ImgLe from './img/img_le.svg?react'; import ImgLogoLecue from './img/img_logo_lecue.svg?react'; import ImgModalEx from './img/img_modal_ex.svg?react'; +import ImgSaleprice from './img/img_saleprice.svg?react'; import ImgSplashLogo from './img/img_splash_logo.svg?react'; import ImgStarOrangeLine from './img/img_star_orangeline.svg?react'; import ImgStarPosit from './img/img_star_postit.svg?react'; @@ -43,6 +49,7 @@ export { IcArrowLeftBlack, IcArrowLeftWhite, IcCamera, + IcCheck, IcCrown, IcDate, IcHome, @@ -50,6 +57,10 @@ export { IcSharing, IcX, ImgBook, + ImgBookBackgray, + ImgBookOrange, + ImgBookOrangeBig, + ImgEvent, ImgKakao01, ImgKakao02, ImgKakao03, @@ -61,6 +72,7 @@ export { ImgLe, ImgLogoLecue, ImgModalEx, + ImgSaleprice, ImgSplashLogo, ImgStarOrangeLine, ImgStarPosit,