Skip to content

Commit

Permalink
Feat : 슬라이더 구현 #5
Browse files Browse the repository at this point in the history
  • Loading branch information
youdame committed May 9, 2024
1 parent db7d19b commit 4293553
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 32 deletions.
5 changes: 5 additions & 0 deletions public/icons/home/icon-left-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 14 additions & 5 deletions src/app/home/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import MovieSection from "@/components/home/MovieSection";
import { MovieCategory } from "@/types/home";
import { getMovies } from "@/api/home";
import { MovieCategory } from "@/types/common";

const HomePage = () => {
const categories: MovieCategory[] = ["upcoming", "popular", "top_rated", "now_playing"];
const HomePage = async () => {
const categories: MovieCategory[] = ["upcoming", "now_playing", "popular", "top_rated"];
const fetchPromises = categories.map((category) => getMovies(category));

const moviesResults = await Promise.all(fetchPromises);

const moviesData = categories.map((category, index) => ({
category,
data: moviesResults[index],
}));

return (
<div className="flex-column gap-22pxr w-full pl-16pxr">
{categories.map((category) => (
<MovieSection key={category} category={category} />
{moviesData.map(({ category, data }) => (
<MovieSection key={category} category={category} movieData={data} />
))}
</div>
);
Expand Down
79 changes: 54 additions & 25 deletions src/components/home/MovieSection.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,65 @@
import { getMovies } from "@/api/home";
import { movieSectionTitle } from "@/constants/movies";
"use client";
import Image from "next/image";
import Link from "next/link";
import { useRef } from "react";
import { movieSectionTitle } from "@/constants/movies";
import { MovieCategory } from "@/types/common";
import { GetMoviesResponse } from "@/types/home";
import ArrowIcon from "#/icons/home/icon-left-arrow.svg";

interface MovieSectionProps {
category: MovieCategory;
movieData: GetMoviesResponse;
}

const MovieSection = async ({ category }: { category: keyof typeof movieSectionTitle }) => {
const moviesData = await getMovies(category);
const posterBaseUrl = process.env.NEXT_POSTER_BASE_URL;
const MovieSection = ({ category, movieData }: MovieSectionProps) => {
const posterBaseUrl = process.env.NEXT_PUBLIC_POSTER_BASE_URL;

// 조건부 스타일 적용을 위한 변수
const isPreview = category === "upcoming";
const titleStyle = isPreview ? "text-26pxr font-bold" : "text-21pxr font-bold"; // 글씨 크기 조정
const imageWrapperStyle = isPreview ? "min-w-102pxr h-102pxr" : "min-w-103pxr h-161pxr"; // 이미지 스타일 조정
const imageStyle = isPreview ? "rounded-full" : "rounded-sm"; // 이미지 스타일 조정
const titleStyle = isPreview ? "text-26pxr font-bold" : "text-21pxr font-bold";
const imageWrapperStyle = isPreview ? "min-w-102pxr h-102pxr" : "min-w-103pxr h-161pxr";
const imageStyle = isPreview ? "rounded-full" : "rounded-sm";

// 스크롤을 위한 ref
const containerRef = useRef<HTMLDivElement>(null);

// 슬라이더 버튼 클릭 이벤트 핸들러
const handleScroll = (direction: "left" | "right") => {
if (containerRef.current) {
const { scrollLeft, clientWidth } = containerRef.current;
const scrollTo = direction === "left" ? scrollLeft - clientWidth : scrollLeft + clientWidth;
containerRef.current.scrollTo({ left: scrollTo, behavior: "smooth" });
}
};

return (
<section className="flex-column w-full gap-14pxr">
<h2 className={titleStyle}>{movieSectionTitle[category]}</h2>
<div className="flex gap-7pxr overflow-auto">
{moviesData.results.map((movie) => {
if (!movie.poster_path) return null;
return (
<Link href={`/media/${movie.id}`} key={movie.id} className={`${imageWrapperStyle} relative`}>
<Image
alt={`영화 포스터 이미지: ${movie.title}`}
fill
className={imageStyle}
src={`${posterBaseUrl}${movie.poster_path}`}
/>
</Link>
);
})}
<section className="flex-center w-full relative">
<button onClick={() => handleScroll("left")} aria-label="Scroll Left">
<ArrowIcon className="absolute left-0 z-10" />
</button>

<div className="flex-column w-full gap-14pxr">
<h2 className={titleStyle}>{movieSectionTitle[category]}</h2>
<div className="flex gap-7pxr overflow-auto scroll-smooth" ref={containerRef}>
{movieData.results.map((movie) => {
if (!movie.poster_path) return null;
return (
<Link href={`/media/${movie.id}`} key={movie.id} className={`${imageWrapperStyle} relative`}>
<Image
alt={`영화 포스터 이미지: ${movie.title}`}
fill
className={imageStyle}
sizes={isPreview ? "102px" : "103px"}
src={`${posterBaseUrl}${movie.poster_path}`}
/>
</Link>
);
})}
</div>
</div>
<button onClick={() => handleScroll("right")} aria-label="Scroll Right">
<ArrowIcon className="rotate-180 absolute right-3pxr z-10" />
</button>
</section>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/types/svgr.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
declare module '*.svg' {
import type { ReactElement, SVGProps } from 'react';
declare module "*.svg" {
import type { ReactElement, SVGProps } from "react";

const content: (props: SVGProps<SVGElement> & { alt: string }) => ReactElement;
export default content;
Expand Down

0 comments on commit 4293553

Please sign in to comment.