diff --git a/src/App.css b/src/App.css index 7d5209f2..f326baa1 100644 --- a/src/App.css +++ b/src/App.css @@ -1,7 +1,7 @@ body { background-color: #e2e8f0; margin: 0; - font-family: "Noto Sans KR", sans-serif; + font-family: "Pretendard", "Noto Sans KR", sans-serif; } .App { @@ -10,7 +10,7 @@ body { } .page-title { - font-size: 24px; + font-size: 30px; font-weight: bold; color: #8c02e2; margin-bottom: 20px; @@ -24,14 +24,15 @@ body { } .movie-card { - width: 120px; - background-color: #308cca; + height: auto; + width: 150px; + background-color: #9c47e7; color: white; - border-radius: 6px; + border-radius: 10px; display: flex; flex-direction: column; align-items: center; - padding-bottom: 10px; + padding-bottom: 15px; transition: transform 0.2s ease; } @@ -39,16 +40,6 @@ body { transform: scale(1.05); } -.poster-box { - width: 100%; - height: 160px; - background-color: #1b6ca8; - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; -} - .poster-box img { width: 100%; height: 100%; diff --git a/src/App.jsx b/src/App.jsx index cd8df10b..36fb532d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,14 +1,18 @@ import "./App.css"; import React, { useState } from "react"; import MovieCard from "./component/MovieCard"; -import { Link } from "react-router-dom"; +import { Link, useSearchParams } from "react-router-dom"; import { useEffect } from "react"; function App() { const [movies, setMovies] = useState([]); + const [loading, setLoading] = useState(false); + const [searchParams] = useSearchParams(); + const query = searchParams.get("query"); useEffect(() => { const fetchMovies = async () => { + setLoading(true); try { const options = { method: "GET", @@ -18,44 +22,62 @@ function App() { }, }; - const response = await fetch( - "https://api.themoviedb.org/3/discover/movie?include_adult=false&include_video=false&language=en-US&page=1&sort_by=popularity.desc", - options - ); + let url = ""; + + if (query && query.trim() !== "") { + url = `https://api.themoviedb.org/3/search/movie?query=${encodeURIComponent( + query + )}&include_adult=false&language=en-US&page=1`; + } else { + url = + "https://api.themoviedb.org/3/discover/movie?include_adult=false&include_video=false&language=en-US&page=1&sort_by=popularity.desc"; + } + + const response = await fetch(url, options); const data = await response.json(); - const filteredMovies = data.results.filter( - (movie) => movie.adult === false - ); + const filteredMovies = data.results + ? data.results.filter((movie) => movie.adult === false) + : []; setMovies(filteredMovies); } catch (error) { console.error("데이터 불러오는 중 오류가 발생했습니다", error); + } finally { + setLoading(false); } }; fetchMovies(); - }, []); + }, [query]); return ( <>

MovieCard

-
- {movies.map((movie) => ( - - - - ))} -
+ {loading ? ( +

로딩중

+ ) : ( +
+ {movies.length > 0 ? ( + movies.map((movie) => ( + + + + )) + ) : ( +

검색 결과가 없습니다.

+ )} +
+ )}
); diff --git a/src/component/MovieDetail.css b/src/component/MovieDetail.css index 99754f5d..25dccefe 100644 --- a/src/component/MovieDetail.css +++ b/src/component/MovieDetail.css @@ -37,19 +37,20 @@ /* 상세 내용 영역 */ .detail-content { display: flex; - align-items: flex-start; + align-items: center; justify-content: center; - gap: 40px; - padding: 40px; background-color: #111; - flex-wrap: wrap; /* ✅ 반응형 정렬 */ + flex-wrap: wrap; } .poster-box img { - width: 300px; - height: auto; + width: 150px; + height: 250px; border-radius: 10px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); + margin: 10px; + justify-self: start; + align-items: flex-start; } .info-box { diff --git a/src/component/NavBar.css b/src/component/NavBar.css index 916c8bb1..1d777149 100644 --- a/src/component/NavBar.css +++ b/src/component/NavBar.css @@ -49,3 +49,12 @@ display: flex; align-items: center; } + +.logo-link { + text-decoration: none; + color: inherit; +} + +.logo-link:hover { + opacity: 0.8; +} diff --git a/src/component/NavBar.jsx b/src/component/NavBar.jsx index 1deaee6c..ec2a4bb3 100644 --- a/src/component/NavBar.jsx +++ b/src/component/NavBar.jsx @@ -1,11 +1,33 @@ -import { Link } from "react-router-dom"; +import { Link, useSearchParams } from "react-router-dom"; import "./NavBar.css"; +import { useState } from "react"; +import useDebounce from "../hooks/useDebounce"; +import { useEffect } from "react"; function NavBar() { + const [input, setInput] = useState(""); + const [searchParams, setSearchParams] = useSearchParams(); + const debouncedInput = useDebounce(input, 500); + + useEffect(() => { + const q = searchParams.get("query") || ""; + setInput(q); + }, []); + + useEffect(() => { + if (debouncedInput && debouncedInput.trim() !== "") { + setSearchParams({ query: debouncedInput.trim() }); + } else { + setSearchParams({}); + } + }, [debouncedInput, setSearchParams]); + return (