,
+ labelEl: HTMLSpanElement,
+ scoreEl: HTMLSpanElement,
+ index: number,
+ ) {
+ stars.forEach((star, i) => {
+ if (i < index) {
+ star.src = starFilledImg;
+ } else {
+ star.src = starEmptyImg;
+ }
+ });
+ const score = index * 2;
+ labelEl.textContent = star_score[score];
+ scoreEl.textContent = `(${score}/10)`;
+ }
+
+ close() {
+ this.div.classList.remove("active");
+ }
+}
diff --git a/src/features/View/MovieList.ts b/src/features/View/MovieList.ts
index 8b67b276a..9754d627f 100644
--- a/src/features/View/MovieList.ts
+++ b/src/features/View/MovieList.ts
@@ -17,12 +17,6 @@ export default class MovieList {
if (mainTitle) mainTitle.textContent = title;
}
- updateMoreButton(totalPages: number, currentPage: number): void {
- const moreButton = document.querySelector(".btn-more") as HTMLButtonElement;
- if (!moreButton) return;
- moreButton.style.display = totalPages === currentPage ? "none" : "block";
- }
-
showEmpty() {
this.movieContainer!.innerHTML = `
@@ -44,6 +38,20 @@ export default class MovieList {
}
}
+ appendSkeletons(count: number = 20) {
+ for (let i = 0; i < count; i++) {
+ const skeleton = new MovieSkeleton().render();
+ skeleton.classList.add("skeleton-item");
+ this.movieList?.append(skeleton);
+ }
+ }
+
+ removeSkeletons() {
+ this.movieList
+ ?.querySelectorAll(".skeleton-item")
+ .forEach((el) => el.remove());
+ }
+
renderMovieList(movies: { results: Movie[] }) {
movies.results.forEach((movie: Movie) => {
this.movieList?.append(new MovieCard(movie).render());
diff --git a/src/features/eventHandler.ts b/src/features/eventHandler.ts
index 58117c35e..da4821ec6 100644
--- a/src/features/eventHandler.ts
+++ b/src/features/eventHandler.ts
@@ -1,8 +1,24 @@
import { movieState } from "./movieState";
-import { initialRender, renderMoreMovies, renderSearchResults } from "./movieController";
+import {
+ initialRender,
+ renderMoreMovies,
+ renderSearchResults,
+ renderMovieDetailModal,
+ closeMovieDetailModal,
+} from "./movieController";
import { Header } from "./View/Header";
export function initEvents() {
+ loadHeader();
+
+ loadSearch();
+
+ loadInfiniteScroll();
+
+ loadMovieDetailInfo();
+}
+
+function loadHeader() {
const header = document.querySelector(".header") as HTMLElement;
header.addEventListener("click", async (e) => {
@@ -12,9 +28,12 @@ export function initEvents() {
await initialRender(movieState.page);
}
});
+}
- // 검색
- const submitContainer = document.querySelector(".background-container") as HTMLFormElement;
+function loadSearch() {
+ const submitContainer = document.querySelector(
+ ".background-container",
+ ) as HTMLFormElement;
submitContainer.addEventListener("submit", async (e: SubmitEvent) => {
e.preventDefault();
movieState.page = 1;
@@ -27,13 +46,57 @@ export function initEvents() {
await renderSearchResults(movieState.page, movieState.searchQuery);
});
+}
+
+function loadInfiniteScroll() {
+ const sentinel = document.querySelector(".scroll-sentinel") as HTMLElement;
+ if (!sentinel) return;
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ const entry = entries[0];
+ if (entry.isIntersecting && !movieState.isLoading && movieState.hasMore) {
+ movieState.page += 1;
+ renderMoreMovies(movieState.page, movieState.searchQuery);
+ }
+
+ // 마지막 페이지면 관찰 중단
+ if (!movieState.hasMore) observer.disconnect();
+ },
+ { rootMargin: "200px" },
+ );
- // 더보기 버튼
- const moreButton = document.querySelector(".btn-more") as HTMLButtonElement;
- if (moreButton) {
- moreButton.addEventListener("click", async () => {
- movieState.page += 1;
- await renderMoreMovies(movieState.page, movieState.searchQuery);
+ observer.observe(sentinel);
+}
+
+// 하나의 영화 카드를 클릭했을 때, 해당 카드에서 영화의 id를 받아서
+// 그 id를 그 영화 정보를 렌더링 하는 함수로 넘겨준다. -> 렌더링 한다.
+function loadMovieDetailInfo() {
+ const movieList = document.querySelector(".thumbnail-list") as HTMLElement;
+ if (movieList) {
+ movieList.addEventListener("click", async (e) => {
+ const target = e.target as HTMLElement; // 클릭된 요소
+ const card = target.closest(".movie-card") as HTMLElement; // 카드 찾기
+ if (card) {
+ const id = card.dataset.id;
+ if (id) await renderMovieDetailModal(Number(id));
+ }
});
}
+
+ document.body.addEventListener("click", (e) => {
+ const target = e.target as HTMLElement;
+ if (
+ target.closest(".close-modal") ||
+ target.classList.contains("modal-background")
+ ) {
+ closeMovieDetailModal();
+ }
+ });
+
+ document.addEventListener("keydown", (e) => {
+ if (e.key === "Escape") {
+ closeMovieDetailModal();
+ }
+ });
}
diff --git a/src/features/movieController.ts b/src/features/movieController.ts
index 02cc1f538..df04a781c 100644
--- a/src/features/movieController.ts
+++ b/src/features/movieController.ts
@@ -1,8 +1,16 @@
import { Header } from "./View/Header";
import MovieList from "./View/MovieList";
-import { getMoreMovies, getPopularMovies, getSearchMovies } from "./movieModel";
+import MovieDetailModal from "./View/MovieDetailModal.ts";
+import {
+ getMoreMovies,
+ getPopularMovies,
+ getSearchMovies,
+ getMovieDetail,
+} from "./movieModel";
+import { movieState } from "./movieState";
const movieList = new MovieList();
+const movieDetailModal = new MovieDetailModal();
export async function initialRender(page: number): Promise {
try {
@@ -15,7 +23,7 @@ export async function initialRender(page: number): Promise {
Header.render(data.results[0]);
movieList.clearList();
movieList.renderMovieList(data);
- movieList.updateMoreButton(data.total_pages, page);
+ movieState.hasMore = page < data.total_pages;
} catch (error) {
if (error instanceof Error) movieList.renderError(error.message);
}
@@ -35,12 +43,12 @@ export async function renderSearchResults(
if (data.results.length === 0) {
movieList.showEmpty();
+ movieState.hasMore = false;
} else {
movieList.clearList();
movieList.renderMovieList(data);
+ movieState.hasMore = page < data.total_pages;
}
-
- movieList.updateMoreButton(data.total_pages, page);
} catch (error) {
if (error instanceof Error) movieList.renderError(error.message);
}
@@ -50,11 +58,34 @@ export async function renderMoreMovies(
page: number,
searchQuery: string,
): Promise {
+ movieState.isLoading = true;
+ movieList.appendSkeletons(20);
try {
const data = await getMoreMovies(page, searchQuery);
+ movieList.removeSkeletons();
movieList.renderMovieList(data);
- movieList.updateMoreButton(data.total_pages, page);
+ movieState.hasMore = page < data.total_pages;
} catch (error) {
+ movieList.removeSkeletons();
if (error instanceof Error) movieList.renderError(error.message);
+ } finally {
+ movieState.isLoading = false;
}
}
+
+// 영화 상세 정보 API를 요청하여 영화 상세 정보 모달을 렌더링하는 함수
+export async function renderMovieDetailModal(id: number) {
+ try {
+ movieDetailModal.reset();
+ // 영화 상세 정보 API 요청
+ const data = await getMovieDetail(id);
+ // 영화 상세 정보 모달 렌더링 함수 호출
+ movieDetailModal.render(data);
+ } catch (error) {
+ if (error instanceof Error) movieList.renderError(error.message);
+ }
+}
+
+export function closeMovieDetailModal() {
+ movieDetailModal.close();
+}
diff --git a/src/features/movieModel.ts b/src/features/movieModel.ts
index d4c88a04e..25165d4a1 100644
--- a/src/features/movieModel.ts
+++ b/src/features/movieModel.ts
@@ -37,3 +37,14 @@ export async function getMoreMovies(page: number, searchQuery: string): Promise<
throw new Error("영화 데이터를 불러오는 중 오류가 발생했습니다.");
}
}
+
+export async function getMovieDetail(id: Number){
+ try{
+ const response = await fetch(`${BASE_URL}/movie/${id}?api_key=${API_KEY}&language=ko-KR`);
+ if (!response.ok) throw new Error(`API 요청 실패: ${response.status}`);
+ return response.json();
+ }
+ catch(error){
+ throw new Error("영화 데이터를 불러오는 중 오류가 발생했습니다.")
+ }
+}
\ No newline at end of file
diff --git a/src/features/movieState.ts b/src/features/movieState.ts
index 41cdea2d1..89abc3821 100644
--- a/src/features/movieState.ts
+++ b/src/features/movieState.ts
@@ -1,8 +1,12 @@
export const movieState = {
page: 1,
searchQuery: "",
+ isLoading: false,
+ hasMore: true,
reset() {
this.page = 1;
this.searchQuery = "";
+ this.isLoading = false;
+ this.hasMore = true;
},
};
diff --git a/src/styles/main.css b/src/styles/main.css
index 893f972c1..b32775bf0 100644
--- a/src/styles/main.css
+++ b/src/styles/main.css
@@ -36,14 +36,14 @@ main {
margin-bottom: 50px;
}
-@media screen and (max-width: 1297px) {
+@media screen and (max-width: 1310px) {
.main-title {
- padding: 48px;
+ font-size: 36px;
}
}
.star {
- width: 24px;
+ width: 16px;
}
button {
@@ -60,7 +60,6 @@ button.primary {
}
#wrap {
- min-width: 1440px;
background-color: var(--color-bluegray-100);
}
@@ -73,6 +72,8 @@ button.primary {
.container {
max-width: 1280px;
margin: 0 auto;
+ width: 100%;
+ padding: 0 24px;
}
.search-container {
@@ -94,11 +95,26 @@ button.primary {
opacity: 1;
}
-@media screen and (max-width: 800px) {
+@media screen and (max-width: 768px) {
.search-container {
- flex-direction: column;
margin-top: 90px;
- margin-left: 75px;
+ justify-content: center;
+ display: flex;
+ align-items: center;
+ padding: 0 24px;
+ }
+
+ .search-form {
+ width: 100%;
+ max-width: 360px;
+ margin-top: 0;
+ }
+
+ .main-title {
+ font-size: 36px;
+ margin-bottom: 56px;
+ text-align: center;
+ padding: 0;
}
}
@@ -115,9 +131,10 @@ button.primary {
color: var(--color-white);
}
-@media screen and (max-width: 1080px) {
+@media screen and (min-width: 769px) and (max-width: 1080px) {
.search-form {
width: 325px;
+ top: 36px;
}
}
@@ -151,6 +168,22 @@ button.primary {
gap: 4px;
}
+@media screen and (max-width: 1024px) {
+ .background-container {
+ padding-left: 48px;
+ height: 420px;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .background-container {
+ padding: 80px 24px 32px;
+ height: auto;
+ min-height: 320px;
+ justify-content: flex-end;
+ }
+}
+
.overlay {
position: absolute;
top: 0;
@@ -166,6 +199,8 @@ button.primary {
z-index: 2;
max-width: 1280px;
margin: 0 auto;
+ width: 100%;
+ padding: 0 24px;
}
.top-rated-movie > *:not(:last-child) {
@@ -180,6 +215,22 @@ h1.logo {
cursor: pointer;
}
+@media screen and (max-width: 1080px) {
+ h1.logo {
+ left: 24px;
+ top: 48px;
+ font-size: 1.5rem;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ h1.logo {
+ left: 24px;
+ top: 20px;
+ font-size: 1.5rem;
+ }
+}
+
.rate {
display: flex;
align-items: baseline;
@@ -202,6 +253,18 @@ span.rate-value {
font-weight: bold;
}
+@media screen and (max-width: 1024px) {
+ .title {
+ font-size: 2.2rem;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .title {
+ font-size: 1.6rem;
+ }
+}
+
footer.footer {
min-height: 180px;
background-color: var(--color-bluegray-80);
diff --git a/src/styles/modal.css b/src/styles/modal.css
index 240a7a37c..e393591a7 100644
--- a/src/styles/modal.css
+++ b/src/styles/modal.css
@@ -16,7 +16,7 @@ body.modal-open {
display: flex;
justify-content: center;
align-items: center;
- z-index: 10;
+ z-index: 1000;
visibility: hidden; /* 모달이 기본적으로 보이지 않도록 설정 */
opacity: 0;
transition:
@@ -29,6 +29,11 @@ body.modal-open {
opacity: 1;
}
+hr {
+ border: 1px solid #67788e;
+ width: 100%;
+}
+
.modal {
background-color: var(--color-bluegray-90);
padding: 20px;
@@ -36,7 +41,161 @@ body.modal-open {
color: white;
z-index: 2;
position: relative;
- width: 1000px;
+ width: min(1000px, calc(100vw - 32px));
+ max-height: 90vh;
+ overflow-y: auto;
+}
+
+.modal-container {
+ width: 100%;
+ opacity: 1;
+ padding-top: 40px;
+ padding-right: 24px;
+ padding-bottom: 40px;
+ padding-left: 24px;
+ gap: 24px;
+ border-radius: 16px;
+}
+
+.modal-title {
+ font-family: DM Sans;
+ font-weight: 700;
+ font-style: Bold;
+ font-size: 32px;
+ line-height: 100%;
+ letter-spacing: 0%;
+}
+
+.modal-release-date-and-genres {
+ font-family: DM Sans;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 20px;
+ line-height: 100%;
+ letter-spacing: 0%;
+}
+
+.modal-rating-text {
+ font-size: 20px;
+ margin: 0;
+ margin-right: 16px;
+ font-family: DM Sans;
+ font-weight: 400;
+ font-style: Regular;
+ font-size: 20px;
+ line-height: 100%;
+ letter-spacing: 0%;
+ padding-top: 2px;
+}
+
+.star-rating {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.stars-row {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.rating-text {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.modal-star {
+ width: 32px;
+ height: 32px;
+}
+
+.rating-label {
+ font-family: Montserrat;
+ font-weight: 600;
+ font-style: SemiBold;
+ font-size: 24px;
+ line-height: 100%;
+ letter-spacing: 0.18px;
+ margin-left: 10px;
+ margin-top: 5px;
+}
+
+.rating-score {
+ font-family: Montserrat;
+ font-weight: 600;
+ font-style: SemiBold;
+ font-size: 24px;
+ line-height: 100%;
+ letter-spacing: 0.18px;
+ color: #95a1b2;
+ margin-top: 5px;
+}
+
+.modal-user-rating-text {
+ font-family: Montserrat;
+ font-weight: 600;
+ font-style: SemiBold;
+ font-size: 24px;
+ line-height: 100%;
+ letter-spacing: 0.18px;
+ margin-bottom: 24px;
+}
+
+.modal-overview-title {
+ font-family: Montserrat;
+ font-weight: 600;
+ font-style: SemiBold;
+ font-size: 24px;
+ line-height: 100%;
+ letter-spacing: 0.18px;
+}
+
+.modal-overview {
+ font-family: Montserrat;
+ font-weight: 300;
+ font-style: Light;
+ font-style: Bold;
+ font-size: 24px;
+ line-height: 147%;
+ letter-spacing: 0.18px;
+ max-height: 218px;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.modal-overview::-webkit-scrollbar {
+ width: 6px;
+}
+
+.modal-overview::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.modal-overview::-webkit-scrollbar-thumb {
+ background: rgba(255, 255, 255, 0.3);
+ border-radius: 3px;
+}
+
+.modal-rating {
+ margin: 0;
+ margin-left: 2px;
+ color: #ffc700;
+ font-family: Montserrat;
+ font-weight: 600;
+ font-size: 24px;
+ line-height: 1;
+ letter-spacing: 0.18px;
+ padding-top: 1.5px;
+ font-style: SemiBold;
+ line-height: 100%;
+}
+
+.average-star {
+ width: 24px;
+ height: 24px;
+ margin-right: 2.5px;
}
.close-modal {
@@ -50,6 +209,8 @@ body.modal-open {
color: white;
font-size: 20px;
cursor: pointer;
+ width: 25px;
+ height: 25px;
}
.modal-container {
@@ -61,11 +222,28 @@ body.modal-open {
border-radius: 16px;
}
+.modal-image {
+ width: 400px;
+ height: 600px;
+ flex-shrink: 0;
+ opacity: 1;
+ border-radius: 16px;
+}
+
+.average {
+ display: flex;
+ align-items: center;
+ line-height: 1;
+}
+
.modal-description {
+ display: flex;
+ flex-direction: column;
width: 100%;
padding: 8px;
margin-left: 16px;
line-height: 1.6rem;
+ gap: 16px;
}
.modal-description .rate > img {
@@ -86,3 +264,218 @@ body.modal-open {
max-height: 430px;
overflow-y: auto;
}
+
+/* 태블릿 */
+@media screen and (min-width: 390px) and (max-width: 1024px) {
+ .modal-background {
+ align-items: flex-end;
+ }
+
+ .modal {
+ width: 100vw;
+ max-height: 140vh;
+ border-radius: 16px 16px 0 0;
+ padding: 16px 24px;
+ overflow-y: hidden;
+ }
+
+ .modal-container {
+ flex-direction: column;
+ align-items: center;
+ padding: 12px 0;
+ gap: 20px;
+ }
+
+ /* 포스터: 중앙 정렬, 작게 */
+ .modal-image {
+ width: 150px;
+ height: auto;
+ flex-shrink: 0;
+ }
+
+ .modal-image img {
+ width: 110px;
+ height: auto;
+ border-radius: 8px;
+ object-fit: cover;
+ }
+
+ /* 설명 영역 전체 */
+ .modal-description {
+ width: 100%;
+ margin-left: 0;
+ padding: 0;
+ gap: 6px;
+ align-items: center;
+ }
+
+ /* 제목/장르/평균 별점: 중앙 */
+ .modal-title {
+ font-size: 28px;
+ text-align: center;
+ }
+
+ .modal-release-date-and-genres {
+ font-size: 16px;
+ text-align: center;
+ }
+
+ .average {
+ justify-content: center;
+ }
+
+ .modal-rating {
+ font-size: 16px;
+ }
+
+ .average-star {
+ width: 14px;
+ height: 14px;
+ }
+
+ /* 내 별점 + 줄거리: 왼쪽 정렬 */
+ .modal-user-rating {
+ width: 100%;
+ text-align: left;
+ }
+
+ .modal-user-rating-text {
+ font-size: 20px;
+ margin-bottom: 10px;
+ margin-left: 2px;
+ }
+
+ .modal-rating-text {
+ font-size: 16px;
+ }
+
+ .rating-label,
+ .rating-score {
+ font-size: 20px;
+ margin-bottom: 2px;
+ }
+
+ .modal-star {
+ width: 20px;
+ height: 20px;
+ }
+
+ .modal-overview-title {
+ width: 100%;
+ font-size: 20px;
+ text-align: left;
+ }
+
+ .modal-overview {
+ width: 100%;
+ font-size: 20px;
+ max-height: 80px;
+ overflow-y: auto;
+ text-align: left;
+ }
+}
+
+/* 모바일 */
+@media screen and (max-width: 390px) {
+ .modal-background {
+ align-items: flex-end;
+ }
+
+ .modal {
+ width: 100vw;
+ border-radius: 16px 16px 0 0;
+ padding: 24px;
+ overflow-y: hidden;
+ }
+
+ .modal-container {
+ flex-direction: column;
+ align-items: center;
+ padding: 12px 0;
+ gap: 12px;
+ }
+
+ /* 이미지 숨김 */
+ .modal-image {
+ display: none;
+ }
+
+ .modal-description {
+ width: 100%;
+ margin-left: 0;
+ padding: 0;
+ gap: 10px;
+ align-items: center;
+ }
+
+ .modal-title {
+ font-size: 20px;
+ text-align: center;
+ padding: 0 36px;
+ }
+
+ .modal-release-date-and-genres {
+ font-size: 16px;
+ text-align: center;
+ }
+
+ .average {
+ justify-content: center;
+ }
+
+ /* 내 별점: 중앙 정렬 */
+ .modal-user-rating {
+ width: 100%;
+ align-items: center;
+ text-align: center;
+ flex-direction: column;
+ }
+
+ .modal-user-rating-text {
+ font-size: 18px;
+ margin-bottom: 8px;
+ }
+
+ .star-rating {
+ flex-direction: column;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .modal-star {
+ width: 28px;
+ height: 28px;
+ }
+
+ .rating-label,
+ .rating-score {
+ font-size: 18px;
+ }
+
+ .modal-rating {
+ font-size: 20px;
+ }
+
+ .modal-rating-text {
+ font-size: 16px;
+ }
+
+ .average-star {
+ width: 16px;
+ height: 16px;
+ }
+
+ /* 줄거리 제목: 중앙, 본문: 왼쪽 */
+ .modal-overview-title {
+ width: 100%;
+ font-size: 18px;
+ text-align: center;
+ }
+
+ .modal-overview {
+ width: 100%;
+ font-size: 18px;
+ max-height: none;
+ text-align: left;
+ }
+}
diff --git a/src/styles/thumbnail.css b/src/styles/thumbnail.css
index fa3b5432d..dbcbe1975 100644
--- a/src/styles/thumbnail.css
+++ b/src/styles/thumbnail.css
@@ -3,32 +3,47 @@
.thumbnail-list {
margin: 0 auto 56px;
display: grid;
- grid-template-columns: repeat(5, 200px);
- gap: 70px;
+ grid-template-columns: repeat(5, 1fr);
+ gap: 72px;
}
@media screen and (max-width: 1310px) {
.thumbnail-list {
grid-template-columns: repeat(4, 1fr);
+ gap: 53px;
}
}
-@media screen and (max-width: 1080px) {
+@media screen and (max-width: 1050px) {
.thumbnail-list {
grid-template-columns: repeat(3, 1fr);
+ gap: 70px;
+ margin-bottom: 40px;
}
}
-@media screen and (max-width: 800px) {
+@media screen and (max-width: 769px) {
.thumbnail-list {
grid-template-columns: repeat(2, 1fr);
+ gap: 70px;
+ margin-bottom: 70px;
+ }
+}
+
+@media screen and (max-width: 653px) {
+ .thumbnail-list {
+ grid-template-columns: repeat(1, 1fr);
+ gap: 70px;
}
}
.thumbnail {
- width: 200px;
- height: 300px;
+ width: 100%;
+ aspect-ratio: 2 / 3;
+ height: auto;
border-radius: 8px;
+ object-fit: cover;
+ display: block;
}
.item {
@@ -37,6 +52,7 @@
display: flex;
flex-direction: column;
gap: 10px;
+ width: 100%;
}
.item-desc {
@@ -67,6 +83,60 @@ p.rate > span {
}
.item .star {
- width: 16px;
+ width: 18px;
+ height: 18px;
top: 1px;
}
+
+/* Skeleton */
+@keyframes skeleton-shimmer {
+ 0% {
+ background-position: -400px 0;
+ }
+ 100% {
+ background-position: 400px 0;
+ }
+}
+
+.movie-skeleton {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ width: 100%;
+}
+
+.movie-skeleton__poster,
+.movie-skeleton__title,
+.movie-skeleton__info {
+ background: linear-gradient(
+ 90deg,
+ var(--color-bluegray-80) 25%,
+ var(--color-bluegray-90) 50%,
+ var(--color-bluegray-80) 75%
+ );
+ background-size: 800px 100%;
+ animation: skeleton-shimmer 1.4s infinite linear;
+ border-radius: 4px;
+}
+
+.movie-skeleton__poster {
+ width: 100%;
+ aspect-ratio: 2 / 3;
+ border-radius: 8px;
+}
+
+.movie-skeleton__details {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.movie-skeleton__title {
+ height: 20px;
+ width: 80%;
+}
+
+.movie-skeleton__info {
+ height: 16px;
+ width: 50%;
+}
diff --git a/types/types.ts b/types/types.ts
index 6e2f484c8..2fc135e26 100644
--- a/types/types.ts
+++ b/types/types.ts
@@ -5,3 +5,9 @@ export interface Movie {
vote_average: number;
backdrop_path: string;
}
+
+export interface MovieDetail extends Movie {
+ overview: string;
+ genres: {id: number, name : string}[];
+ release_date : string;
+}