gemini "src/components/Home.jsx를 작성해줘. useOutletContext로 now, popular, topRated, loading 데이터를 받아야 해. 상단에는 배경 영상([영상 파일명])과 인기영화 첫 번째 항목을 히어로로 표시하고, 하단에는 현재 상영작/인기 영화/최고 평점 3개의 Section 컴포넌트를 보여줘. 로딩 중에는 Spinner를 표시해줘."
[영상 파일명]을 public 폴더에 넣은 동영상 파일 이름으로 바꾼다(예: video.mp4).
1. Home 페이지의 구조
GOFLEX의 메인 페이지는 두 가지 영역으로 나뉜다.
히어로(Hero) 영역 — 배경 영상 + 인기 영화 하이라이트 + "자세히 보기" 버튼
영화 목록 영역 — 현재 상영작, 인기 영화, 최고 평점 3개 섹션
순서
만들 기능
핵심 개념
1단계
import + 데이터 받기
useOutletContext
2단계
히어로 영역
비디오 배경, 조건부 렌더링
3단계
영화 목록 영역
Section 재사용, loading 처리
2. 1단계 — import + 데이터 받기
src/components/Home.jsx 파일을 열고 임시 코드를 모두 지운 뒤 아래를 작성한다.
import { useOutletContext, Link } from "react-router";
import { Section } from "./Section.jsx";
import { Spinner } from "./UI.jsx";
export function Home() {
const { now, popular, topRated, loading } = useOutletContext();
// 인기영화 첫 번째를 히어로에 표시
const hero = popular.length > 0 ? popular[0] : null;
줄
설명
1
useOutletContext(유즈아울렛컨텍스트)로 5편에서 App.jsx가 Outlet의 context prop으로 전달한 데이터를 받는다. Link는 히어로의 "자세히 보기" 버튼에 사용한다.
3
4편에서 만든 Spinner 컴포넌트를 가져온다. 데이터가 아직 도착하지 않았을 때 "불러오는 중…" 메시지를 표시한다.
6
객체 구조 분해(Destructuring, 디스트럭처링) — 객체에서 필요한 프로퍼티를 개별 변수로 추출하는 문법이다. useOutletContext()가 반환한 객체에서 now, popular, topRated, loading을 각각 변수로 꺼낸다.
8
삼항 연산자(조건 ? 참 : 거짓)이다. popular 배열에 요소가 있으면 첫 번째 요소(popular[0])를 hero에 저장하고, 없으면 null을 저장한다.
3. 2단계 — 히어로 영역
같은 Home.jsx 파일에서, 1단계의 hero 변수 선언 바로 아래에 return을 작성한다. 히어로 영역은 세 겹의 레이어(배경 영상 → 오버레이 → 텍스트)로 구성된다. position: absolute 요소를 겹쳐서 레이어를 구성하는 CSS 포지셔닝 기법이다.
relative — CSS position: relative이다. 자식 요소 중 position: absolute인 요소의 기준 컨테이너가 된다. h-screen은 뷰포트 전체 높이를 차지한다. overflow-hidden은 자식 요소가 영역을 벗어나면 잘라낸다.
4
absolute top-0 left-0 — CSS position: absolute이다. 가장 가까운 relative 부모를 기준으로 좌상단에 위치한다. object-cover는 가로세로 비율을 유지하면서 컨테이너를 꽉 채운다. autoPlay muted loop playsInline은 자동 재생, 음소거, 반복, 모바일 인라인 재생 속성이다.
5
bg-black/50 — 50% 투명한 검정 막을 영상 위에 덮는다. 글자가 잘 보이도록 배경을 어둡게 만든다.
히어로 텍스트 + 인기영화
<div className="relative container mx-auto flex flex-col justify-center items-center h-full text-center px-6">
<h2 className="text-5xl md:text-7xl lg:text-9xl font-bold text-yellow-400">GOFLEX</h2>
<p className="text-xl md:text-2xl text-white mt-4">최신 영화와 인기 작품을 만나보세요.</p>
{hero && (
<div className="mt-8 flex flex-col items-center gap-3">
<p className="text-gray-300 text-lg">지금 인기 있는 영화</p>
<h3 className="text-3xl md:text-4xl font-bold text-white">{hero.title}</h3>
<Link to={`/movie/${hero.id}`} className="mt-2 bg-yellow-400 text-black px-8 py-3 rounded-lg font-bold hover:bg-yellow-300 transition-colors">
자세히 보기
</Link>
</div>
)}
</div>
</section>
줄
설명
1
relative — 내부 absolute 요소의 기준 컨테이너이다. container mx-auto — 최대 너비 제한 + 가로 중앙 배치이다. flex flex-col — 자식 요소를 세로 방향으로 배치한다. justify-center items-center — 세로·가로 모두 가운데 정렬한다.
2
text-5xl md:text-7xl lg:text-9xl — 반응형 글꼴 크기이다. md:는 768px 이상, lg:는 1024px 이상에서 적용된다.
4-12
hero && (...) — 논리 AND 단축 평가(Short-circuit evaluation)이다. && 연산자는 왼쪽이 null, undefined, false 등 거짓 값이면 오른쪽을 평가하지 않고 건너뛴다. hero에 값이 있을 때만 인기 영화 정보가 렌더링된다.
8
Link to={...} — 클릭 시 /movie/{hero.id} 경로로 이동한다. hover:bg-yellow-300 — 마우스 오버 시 배경색이 밝아지는 CSS 가상 클래스이다.
4. 3단계 — 영화 목록 영역
같은 Home.jsx 파일에서, 히어로 </section> 태그 바로 아래에 이어서 작성한다. loading 상태에 따라 스피너 또는 영화 목록을 조건부 렌더링한다.
loading이 true이면 Spinner 컴포넌트로 "불러오는 중…" 텍스트를 표시한다.
3-8
!(NOT 연산자)는 불린 값을 반전시킨다. loading이 true이면 !loading은 false, loading이 false이면 !loading은 true가 된다. 로딩이 끝났을 때(false) 3개의 Section을 표시한다. category prop은 "더보기" 링크에 사용된다.