티스토리 뷰

기록

React Movies 기록 - 3. Home, latest

als982001 2023. 2. 5. 22:50

1. Home.tsx

import styled from "styled-components";
import { Link } from "react-router-dom";

const Wrapper = styled.div`
  background-color: ${(props) => props.theme.black.darker};
  width: 100vw;
  height: 210vh;
  display: flex;
  flex-direction: column;
`;

const Poster = styled.section`
  width: 100vw;
  height: 70vh;
  background-size: cover;
  background-position: center center;
  display: flex;
  flex-direction: column;
  justify-content: center;
`;

const Introduction = styled.section`
  width: 40%;
  height: 80%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 10px;
  background-color: rgba(73, 85, 121, 0.2);
  border-radius: 20px;
`;

const IntroductionTitle = styled.h1`
  font-size: 55px;
  font-weight: bold;
  color: #a4a4a4;
  margin-bottom: 5px;
`;

const IntroductionOverview = styled.p`
  font-size: 30px;
  font-weight: 300;
  color: #a4a4a4;
`;

const PageBtn = styled.div`
  background-color: ${(props) => props.theme.black.lighter};
  width: 30%;
  height: 35%;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 20px;

  &:hover {
    background-color: ${(props) => props.theme.black.darker};
  }
`;

function Home() {
  return (
    <Wrapper>
      <Poster
        style={{
          alignItems: "end",
          marginTop: "50px",
          backgroundImage: `linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1)), url(https://cdn.pixabay.com/photo/2020/12/28/20/45/frozen-lake-5868472_1280.jpg)`,
        }}
      >
        <Introduction style={{ marginRight: "50px" }}>
          <IntroductionTitle>영화, TV 정보를 한눈에!</IntroductionTitle>
          <IntroductionOverview style={{ height: "80vh" }}>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum
            ut pretium metus. Suspendisse potenti. Phasellus eu hendrerit metus.
            Maecenas fermentum ante auctor ligula tincidunt sagittis. Morbi
            aliquet metus vel augue porttitor cursus sit amet vitae libero. Ut
            blandit pharetra augue id vestibulum.
          </IntroductionOverview>
        </Introduction>
      </Poster>
      <Poster
        style={{
          alignItems: "start",
          backgroundImage: `linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1)), url(https://cdn.pixabay.com/photo/2022/12/30/10/47/typewriter-7686633_1280.jpg)`,
        }}
      >
        <Introduction style={{ marginLeft: "50px" }}>
          <IntroductionTitle>영화 확인하기</IntroductionTitle>
          <IntroductionOverview style={{ height: "100vh" }}>
            Ut suscipit, nisi non eleifend bibendum, purus erat pulvinar augue,
            convallis efficitur massa leo molestie purus. Curabitur nec mauris
            ullamcorper, vulputate turpis nec, tristique neque. Praesent
            euismod, erat quis tincidunt maximus, nisi elit aliquet risus, non
            ultricies nisl purus et ex. Aliquam non est risus.
          </IntroductionOverview>
          <PageBtn>
            <Link to="/movies">Movie</Link>
          </PageBtn>
        </Introduction>
      </Poster>
      <Poster
        style={{
          alignItems: "end",
          backgroundImage: `linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1)),url(https://cdn.pixabay.com/photo/2022/12/28/21/10/night-7683839_1280.jpg)`,
        }}
      >
        <Introduction style={{ marginRight: "50px" }}>
          <IntroductionTitle>TV 확인하기</IntroductionTitle>
          <IntroductionOverview style={{ height: "100vh" }}>
            Morbi a mollis nibh. Pellentesque felis libero, sodales finibus
            augue sit amet, consequat lacinia ante. Duis in ligula vel purus
            facilisis viverra. Sed rutrum lacus a mauris molestie, eu pharetra
            est eleifend. Cras eget purus ac quam fringilla congue.
          </IntroductionOverview>
          <PageBtn>
            <Link to="/tvs">Tv</Link>
          </PageBtn>
        </Introduction>
      </Poster>
    </Wrapper>
  );
}

export default Home;

홈화면

 홈화면은 크게 3가지 영역으로 나누었다. 우선, 가장 윗 부분은 이 웹사이트의 간단한 소개글을 보여준다. 그리고 두 번째 부분은 영화 정보를 확인할 수 있는 부분이며 마지막 부분은 tv 정보를 확인할 수 있는 부분이다. 그런데 각 부분의 title의 밑에는 영어로 이상한 글이 작성되어 있는데, 각 영역의 소개글을 뭐라고 작성해야할지 잘 몰라 임시로 로렘 입숨을 이용하였다. 또한 영역의 이미지는 copyfree 이미지를 이용하였다.

 

2. latest.tsx

import { useQuery } from "react-query";
import styled from "styled-components";
import { getLatestMovie, getLatestTv, ILatestMovie, ILatestTv } from "../api";
import { makeImagePath } from "../utils";

const Wrapper = styled.div`
  background: black;
  padding-bottom: 200px;
`;

const Loader = styled.div`
  height: 20vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 30px;
  font-weight: bold;
  margin-top: 50px;
`;

const LatestMedia = styled.section`
  width: 80vw;
  height: 80vh;
  border-radius: 50px;
  background-color: #282a3a;
  margin-bottom: 100px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
`;

const LatestNoPoster = styled.section`
  width: 65%;
  height: 90%;
  background-color: #1a120b;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 20px;
  font-size: 100px;
  font-weight: bold;
`;

const LatestMediaPoster = styled.section<{ bgphoto: string }>`
  width: 65%;
  height: 90%;
  background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 1)),
    url(${(props) => props.bgphoto});
  background-size: cover;
  background-position: center;
  border-radius: 20px;
`;

const LatestMediaInfos = styled.section`
  width: 25%;
  height: 90%;
  background-color: #d8d8d8;
  border-radius: 20px;
  margin-left: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 10px;
  color: #182747;
`;

const Title = styled.p`
  font-size: 35px;
  font-weight: bold;
  margin-bottom: 10px;
`;

const Overview = styled.p`
  font-size: 15px;
  text-align: center;
  margin-bottom: 10px;
`;

const Genres = styled.section`
  width: 100%;
  display: flex;
  justify-content: center;
  margin-bottom: 10px;
`;

const OtherInfo = styled.p`
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 10px;
`;

const Genre = styled.span``;

export default function Latest() {
  const { data: latestMovie, isLoading: latestMovieLoading } =
    useQuery<ILatestMovie>("latestMove", getLatestMovie);
  const { data: latestTv, isLoading: latestTvLoading } = useQuery<ILatestTv>(
    "latestTv",
    getLatestTv
  );

  return (
    <Wrapper
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
      }}
    >
      {latestMovieLoading || latestTvLoading ? (
        <Loader>Loading...</Loader>
      ) : (
        <>
          <LatestMedia style={{ marginTop: "100px" }}>
            {latestMovie.backdrop_path ? (
              <LatestMediaPoster
                bgphoto={makeImagePath(latestMovie.backdrop_path)}
              ></LatestMediaPoster>
            ) : (
              <LatestNoPoster>No Poster</LatestNoPoster>
            )}
            <LatestMediaInfos>
              <Title>{latestMovie.title}</Title>
              <Overview>
                {latestMovie.overview
                  ? latestMovie.overview.length > 100
                    ? latestMovie.overview.slice(0, 100) + "..."
                    : latestMovie.overview
                  : "No Overview"}
              </Overview>
              <Genres>
                {latestMovie.genres.length === 0 ? (
                  <p>No Genre Info</p>
                ) : (
                  latestMovie.genres.map((genre) => (
                    <Genre>{`✺ ${genre.name} `}</Genre>
                  ))
                )}
              </Genres>
              <OtherInfo>{`Status: ${latestMovie.status}`}</OtherInfo>
              <OtherInfo>{`Laugnage: ${latestMovie.original_language}`}</OtherInfo>
              <OtherInfo>{`Popularity: ${latestMovie.popularity}`}</OtherInfo>
              <OtherInfo>{`Vote Average: ${latestMovie.vote_average}`}</OtherInfo>
            </LatestMediaInfos>
          </LatestMedia>
          <LatestMedia>
            {latestTv.backdrop_path ? (
              <LatestMediaPoster
                bgphoto={makeImagePath(latestTv.backdrop_path)}
              ></LatestMediaPoster>
            ) : (
              <LatestNoPoster>No Poster</LatestNoPoster>
            )}
            <LatestMediaInfos>
              <Title>{latestTv.name}</Title>
              <Overview>
                {latestTv.overview
                  ? latestTv.overview.length > 100
                    ? latestTv.overview.slice(0, 100) + "..."
                    : latestTv.overview
                  : "No Overview"}
              </Overview>
              <Genres>
                {latestTv.genres.length === 0 ? (
                  <p>No Genre Info</p>
                ) : (
                  latestTv.genres.map((genre) => (
                    <Genre>{`✺ ${genre.name} `}</Genre>
                  ))
                )}
              </Genres>
              <OtherInfo>{`Status: ${latestTv.status}`}</OtherInfo>
              <OtherInfo>{`Laugnage: ${latestTv.original_language}`}</OtherInfo>
              <OtherInfo>{`Popularity: ${latestTv.popularity}`}</OtherInfo>
              <OtherInfo>{`Vote Average: ${latestTv.vote_average}`}</OtherInfo>
            </LatestMediaInfos>
          </LatestMedia>
        </>
      )}
    </Wrapper>
  );
}

최신 작품

 

 개인적으로 가장 부끄러운 부분이다. 도대체 어떻게 해야 예쁘게 보여줄 수 있을지 수많은 고민을 했지만, 도저히 생각이 나지 않아 우선 위처럼 표현하였다. 작품의 포스터 이미지의 path가 없을 경우 "No Poster"를 보여준다. 

  • const { data: latestMovie, isLoading: latestMovieLoading } = useQuery("latestMove", getLatestMovie); : useQuery를 이용해 api를 fetch한 후 json화한 latest movie 데이터를 받아온다.
  • const { data: latestTv, isLoading: latestTvLoading } = useQuery<ILatestTv>( "latestTv", getLatestTv ); : 위와 같은 방식으로 latest tv 데이터를 받아온다.
  • {latestMovieLoading || latestTvLoading ? ( <Loader>Loading...</Loader> ) : ... : 만약 latest movie, latest tv 중 하나라도 로딩 중이라면 Loading...을 보여준다. 만약 둘 다 로딩이 끝났다면 각 데이터를 보여준다.

참고 사이트

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함