배포 링크: NEMOFLIX
📦src
┣ 📂api
┃ ┣ 📜apiClient.ts
┃ ┗ 📜apiUrl.ts
┣ 📂components
┃ ┣ 📂atoms
┃ ┃ ┣ 📂Button
┃ ┃ ┣ 📂Image
┃ ┃ ┣ 📂Paragraph
┃ ┃ ┣ 📂Typography
┃ ┣ 📂molecules
┃ ┃ ┣ 📂LoaderIcon
┃ ┣ 📂organisms
┃ ┃ ┣ 📂Card
┃ ┃ ┣ 📂Header
┃ ┃ ┣ 📂Sidebar
┃ ┣ 📂pages
┃ ┃ ┣ 📂detail
┃ ┃ ┣ 📂home
┃ ┃ ┣ 📂login
┃ ┣ 📂templates
┃ ┃ ┣ 📂Authorization
┃ ┃ ┣ 📂CategoryLayout
┃ ┃ ┣ 📂TopSectionLayout
┣ 📂constants
┃ ┣ 📜mainPosterUrlList.ts
┃ ┗ 📜windowScreenSizeData.ts
┣ 📂fonts
┃ ┣ 📜font.d.ts
┃ ┗ 📜NetflixFont.ttf
┣ 📂hooks
┃ ┣ 📜useGetCategoryData.ts
┃ ┣ 📜useGetDetailData.ts
┃ ┣ 📜useMoveToNextSlide.ts
┃ ┣ 📜useRouter.ts
┃ ┗ 📜useScrollYPosition.ts
┣ 📂routes
┃ ┗ 📜index.tsx
┣ 📂styles
┃ ┣ 📜GlobalStyle.tsx
┃ ┗ 📜reset.css
┣ 📂types
┃ ┣ 📜apiDataTypes.ts
┃ ┗ 📜categoryLabelList.ts
┣ 📂utils
┃ ┣ 📜makeBgPath.ts
┃ ┣ 📜makeImagePath.ts
┃ ┣ 📜makeRandomMainPoster.ts
┃ ┗ 📜moveToSection.ts
┣ 📜App.tsx
┣ 📜main.tsx
┗ 📜vite-env.d.ts
- home route는 height가 400vh, 4개의 섹션이 100vh씩 나눠가지고 있다.
- 그래서 처음에 개발자 도구로 height값이 얼마인지 확인하였다.
jsx window.scrollTo({ top: 969*0(|| 969*1 || 969*2 || 969*3), //각각 1~4영역 behavior: "smooth", });
- 그런데, 개인마다 가지고 있는 디바이스의 사이즈가 상이하기 때문에 다른 방법을 찾아야 했다.
-
windowScreenSizeData.ts
export const VIEW_HEIGHT = window.innerHeight;
-
moveToSection.ts
import { VIEW_HEIGHT } from "@/constants/windowScreenSizeData"; //TODO: utils디렉토리에 두는게 맞을까? export const moveToSection = (event: React.MouseEvent<HTMLButtonElement>) => { //TODO: 원래는 undefined일 경우 에러, 어떻게 처리하지? const INDEX = event.currentTarget.dataset.index ? +event.currentTarget.dataset.index : -1; window.scrollTo({ top: VIEW_HEIGHT * INDEX, behavior: "smooth", }); };
smooth_scroll.mp4
Pure CSS Loader - Optimized Spinners for Web · Loading.io
- initial/final index 범위 벗어날 경우, disabled 적용
import { useState } from "react";
export const useMoveToNextSlide = () => {
const [cardDataIndex, setCardDataIndex] = useState(0);
const moveToNextSlide = (event: React.MouseEvent<HTMLButtonElement>) => {
//TODO: undefined 가능성 있는 것들을 어떻게 처리해야할지 모르겠다
const INDEX = event.currentTarget.dataset.cardpageindex
? +event.currentTarget.dataset.cardpageindex
: -1;
setCardDataIndex((prev) => {
const calculatedIndex = prev + INDEX;
//TODO: 매직넘버 처리하기(0:INITIAL_INDEX, 18|19: FINAL_INDEX)
if (0 >= calculatedIndex) return 0;
else if (calculatedIndex >= 19) return 18;
return prev + INDEX * 3;
});
};
return { cardDataIndex, moveToNextSlide };
};
const CategoryLayout = ({ variant = "popular", ...rest }: Props) => {
...
const { cardDataIndex, moveToNextSlide } = useMoveToNextSlide();
return (
...
<Button
disabled={cardDataIndex === 0 ? true : false}
variant="NEXT_CATEGORY"
data-cardpageindex={-1}
onClick={moveToNextSlide}
style={{ position: "absolute", top: "15em", left: "4.5em" }}
>◀</Button>
<Button
disabled={cardDataIndex === 18 ? true : false}
variant="NEXT_CATEGORY"
data-cardpageindex={1}
onClick={moveToNextSlide}
style={{ position: "absolute", top: "15em", right: "6em" }}
>▶</Button>
)}
- INITIAL_INDEX, FINAL_INDEX 매직 넘버 처리
- undefined으로 리턴될 수 있는 값들을 어떻게 처리할지 고민하기