Hey Web Developers, Out there In this Project We Will Create a Movie Website Which Will Just Fetch All the Movies From an API. We Will Use the API of TMDB For This Project So Before Starting the Project Make Sure You Create an Account an On TMDM.
Also Read: Web App vs Website | What is the Difference
Creating an Account On TMDM:
- Go to https://www.themoviedb.org/ & Click On the Join TMDM Button
- Sign In By Filling in Your Details And Click On the Sign-Up Button
Once You Have Successfully Signed Up And Created Your Account On TMDB Then Click On the Setting>>API & Generate Your API.
Now the Actual Coding Part Comes, Just Create a New Folder And Create Three Files Name ‘index.html’, ‘style.css’ & ‘app.js’
And Paste the Following Code In the Respective Files, Make Sure You Put Your Own API Key In the app.js File. Where I Have Mentioned Your API KEY
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Movies Info - All About Movies</title>
</head>
<body>
<div class="container">
<nav>
<div class="logo">
<span>Movies Info Net </span>- All About Movies
</div>
<input type="checkbox" id="click">
<label for="click" class="menu-btn">
<i class="fas fa-bars"></i>
</label>
<ul>
<li><a class="active" href="index.html"><i class="fa-solid fa-house"></i> Home</a></li>
</ul>
</nav>
<div class="search">
<input type="text" placeholder="Search Movie...">
<button>Search</button>
</div>
<div class="movies-container favorites">
<h1>Favorites</h1>
<div class="movies-grid">
<!-- <div class="card" data-id="123456">
<div class="img">
<img src="https://unsplash.it/500/1000" alt="">
</div>
<div class="info">
<h2>Movie Name</h2>
<div class="single-info">
<span>Rate: </span>
<span>10 / 10</span>
</div>
<div class="single-info">
<span>Release Date: </span>
<span>10-04-2022</span>
</div>
</div>
</div> -->
</div>
</div>
<div class="movies-container trending">
<h1>Trending</h1>
<div class="movies-grid">
<!-- <div class="card" data-id="123456">
<div class="img">
<img src="https://unsplash.it/500/1000" alt="">
</div>
<div class="info">
<h2>Movie Name</h2>
<div class="single-info">
<span>Rate: </span>
<span>10 / 10</span>
</div>
<div class="single-info">
<span>Release Date: </span>
<span>10-04-2022</span>
</div>
</div>
</div> -->
</div>
</div>
</div>
<div class="popup-container">
<!-- <span class="x-icon">✖</span>
<div class="content">
<div class="left">
<div class="poster-img">
<img src="https://unsplash.it/500/1000" alt="">
</div>
<div class="single-info">
<span>Add to favorites:</span>
<span class="heart-icon">♥</span>
</div>
</div>
<div class="right">
<h1>Movie Title</h1>
<h3>Movie Tagline</h3>
<div class="single-info-container">
<div class="single-info">
<span>Language:</span>
<span>English</span>
</div>
<div class="single-info">
<span>Length:</span>
<span>120 minutes</span>
</div>
<div class="single-info">
<span>Rate:</span>
<span>10 / 10</span>
</div>
<div class="single-info">
<span>Budget:</span>
<span>1350000$</span>
</div>
<div class="single-info">
<span>Release Date:</span>
<span>05-07-2022</span>
</div>
</div>
<div class="genres">
<h2>Genres</h2>
<ul>
<li>Action</li>
<li>Drama</li>
<li>Romance</li>
</ul>
</div>
<div class="overview">
<h2>Overview</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere necessitatibus, quos molestiae fuga voluptatem totam odit voluptates ullam et distinctio?</p>
</div>
<div class="trailer">
<h2>Trailer</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Kmo8NLKkfcQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
</div>
</div> -->
</div>
<script src="app.js"></script>
</body>
</html>
style.css
@import url(https://fonts.googleapis.com/css?family=Poppins:100,100italic,200,200italic,300,300italic,regular,italic,500,500italic,600,600italic,700,700italic,800,800italic,900,900italic);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
background-color: #151515;
}
body::-webkit-scrollbar {
width: 1em;
}
body::-webkit-scrollbar-track {
box-shadow: #fff;
background: #fff;
border-radius: 5px;
}
body::-webkit-scrollbar-thumb {
background-color: #00f5f5;
border-radius: 5px;
}
::selection{
background: #00f5f5;
color: #fff;
}
span{
color: #00f5f5;
}
nav{
display: flex;
height: 80px;
width: 100%;
background: #1b1b1b;
align-items: center;
justify-content: space-between;
padding: 0 50px 0 100px;
flex-wrap: wrap;
}
nav .logo{
color: #fff;
font-size: 35px;
font-weight: 600;
}
nav ul{
display: flex;
flex-wrap: wrap;
list-style: none;
}
nav ul li{
margin: 0 5px;
}
nav ul li a{
color: #f2f2f2;
text-decoration: none;
font-size: 18px;
font-weight: 500;
padding: 8px 15px;
border-radius: 5px;
letter-spacing: 1px;
transition: all 0.3s ease;
}
nav ul li a.active,
nav ul li a:hover{
color: #111;
background: #fff;
}
nav .menu-btn i{
color: #fff;
font-size: 22px;
cursor: pointer;
display: none;
}
input[type="checkbox"]{
display: none;
}
@media (max-width: 1000px){
nav{
padding: 0 40px 0 50px;
}
}
@media (max-width: 920px) {
nav .menu-btn i{
display: block;
}
#click:checked ~ .menu-btn i:before{
content: "\f00d";
}
nav ul{
position: fixed;
top: 80px;
left: -100%;
background: #111;
height: 100vh;
width: 100%;
text-align: center;
display: block;
transition: all 0.3s ease;
}
#click:checked ~ ul{
left: 0;
}
nav ul li{
width: 100%;
margin: 40px 0;
}
nav ul li a{
width: 100%;
margin-left: -100%;
display: block;
font-size: 20px;
transition: 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
#click:checked ~ ul li a{
margin-left: 0px;
}
nav ul li a.active,
nav ul li a:hover{
background: none;
color: cyan;
}
}
.card {
width: clamp(150px, 95vw, 250px);
box-shadow: 0 0 .5rem rgb(0, 255, 255);
outline: 2px solid rgb(0, 255, 255);
overflow: hidden;
color: #fff;
cursor: pointer;
border-radius: .5rem;
}
.img {
width: 100%;
height: 200px;
overflow: hidden;
position: relative;
transition: 200ms ease-in-out transform;
}
.img img {
width: 100%;
height: 100%;
object-fit: cover;
}
.img::before {
content: '';
position: absolute;
bottom: 0;
width: 100%;
height: 30%;
background-image: linear-gradient(to top, #151515, transparent);
}
.info {
padding: 2rem 1rem 1rem;
}
.info h2 {
margin-bottom: 0.5rem;
font-size: 1.3rem;
}
.single-info {
display: flex;
align-items: center;
justify-content: space-between;
font-size: .8rem;
margin: .2rem 0;
}
.card:hover .img {
transform: scale(1.1);
}
.movies-grid {
display: flex;
align-items: flex-start;
justify-content: center;
flex-wrap: wrap;
gap: 2rem;
padding: 1rem;
}
.movies-container {
padding: 1rem;
text-align: center;
color: #fff;
}
.search {
display: flex;
justify-content: center;
column-gap: 1rem;
margin-top: 2rem;
padding: 2rem 0 1rem;
}
.search input,
.search button {
padding: .5rem 1rem;
font-size: 1rem;
background-color: transparent;
border: none;
outline: none;
border: 2px solid rgb(0, 255, 255);
color: #fff;
}
.search button {
cursor: pointer;
}
.search button:hover { background-color: rgb(1, 196, 196); }
.search button:active { transform: scale(.9); }
.popup-container {
position: fixed;
width: 100%;
height: 100%;
/* background-image: linear-gradient(rgba(0, 0, 0, .9), rgba(0, 0, 0, 1)), url(https://unsplash.it/1600/900); */
background-size: cover;
background-position: center;
top: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
padding: 3rem;
overflow-y: scroll;
transform: scale(0);
transition: 200ms ease-in-out transform;
}
.content {
display: flex;
align-items: flex-start;
gap: 3rem;
width: 1200px;
margin-top: 10rem;
}
.content .left .single-info {
font-size: 1rem;
padding: .5rem 0;
}
.content .left .single-info .heart-icon {
font-size: 2rem;
user-select: none;
cursor: pointer;
}
.content .left .single-info .heart-icon:hover { transform: scale(1.1); }
.content .left .single-info .heart-icon:active { transform: scale(.9); }
.poster-img {
width: 300px;
height: 400px;
overflow: hidden;
border-radius: .5rem;
box-shadow: 0 0 .5rem rgba(255, 0, 0, 1);
border: 1px solid rgba(255, 0, 0, 1);
}
.poster-img img {
width: 100%;
height: 100%;
object-fit: cover;
}
.single-info-container { width: 200px; }
.right > *:not(h1) { margin: 1rem 0; }
.trailer iframe {
border: 2px solid rgb(0, 255, 255);
box-shadow: 0 0 .5rem rgb(0, 255, 255);
border-radius: .5rem;
max-width: 400px;
width: 100%;
height: 200px;
}
.x-icon {
font-size: 2rem;
position: absolute;
top: 100px;
right: 100px;
cursor: pointer;
user-select: none;
}
.x-icon:hover { transform: scale(1.3); }
.x-icon:active { transform: scale(1); }
.show-popup { transform: scale(1); }
.change-color { color: #00f5f5; }
@media only screen and (max-width: 800px) {
.popup-container * { padding: 0; }
.popup-container { padding: 2rem; }
.content {
flex-direction: column;
margin-top: 50rem;
}
.x-icon {
top: 10px;
right: 20px;
}
}
app.js
const API_KEY = `YOUR_API_KEY_HERE`
const image_path = `https://image.tmdb.org/t/p/w1280`
// - API key will only be available for this video since I'll delete it right after that but you can go to https://www.themoviedb.org/ , create an account and get a key for free.
// - Image path is only the base url from where we'll get the images.
const input = document.querySelector('.search input')
const btn = document.querySelector('.search button')
const main_grid_title = document.querySelector('.favorites h1')
const main_grid = document.querySelector('.favorites .movies-grid')
const trending_el = document.querySelector('.trending .movies-grid')
const popup_container = document.querySelector('.popup-container')
function add_click_effect_to_card (cards) {
cards.forEach(card => {
card.addEventListener('click', () => show_popup(card))
})
}
// SEARCH MOVIES
async function get_movie_by_search (search_term) {
const resp = await fetch(`https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${search_term}`)
const respData = await resp.json()
return respData.results
}
btn.addEventListener('click', add_searched_movies_to_dom)
async function add_searched_movies_to_dom () {
const data = await get_movie_by_search(input.value)
main_grid_title.innerText = `Search Results...`
main_grid.innerHTML = data.map(e => {
return `
<div class="card" data-id="${e.id}">
<div class="img">
<img src="${image_path + e.poster_path}">
</div>
<div class="info">
<h2>${e.title}</h2>
<div class="single-info">
<span>Rate: </span>
<span>${e.vote_average} / 10</span>
</div>
<div class="single-info">
<span>Release Date: </span>
<span>${e.release_date}</span>
</div>
</div>
</div>
`
}).join('')
const cards = document.querySelectorAll('.card')
add_click_effect_to_card(cards)
}
// POPUP
async function get_movie_by_id (id) {
const resp = await fetch(`https://api.themoviedb.org/3/movie/${id}?api_key=${API_KEY}`)
const respData = await resp.json()
return respData
}
async function get_movie_trailer (id) {
const resp = await fetch(`https://api.themoviedb.org/3/movie/${id}/videos?api_key=${API_KEY}`)
const respData = await resp.json()
return respData.results[0].key
}
async function show_popup (card) {
popup_container.classList.add('show-popup')
const movie_id = card.getAttribute('data-id')
const movie = await get_movie_by_id(movie_id)
const movie_trailer = await get_movie_trailer(movie_id)
popup_container.style.background = `linear-gradient(rgba(0, 0, 0, .8), rgba(0, 0, 0, 1)), url(${image_path + movie.poster_path})`
popup_container.innerHTML = `
<span class="x-icon">✖</span>
<div class="content">
<div class="left">
<div class="poster-img">
<img src="${image_path + movie.poster_path}" alt="">
</div>
<div class="single-info">
<span>Add to favorites:</span>
<span class="heart-icon">♥</span>
</div>
</div>
<div class="right">
<h1>${movie.title}</h1>
<h3>${movie.tagline}</h3>
<div class="single-info-container">
<div class="single-info">
<span>Language:</span>
<span>${movie.spoken_languages[0].name}</span>
</div>
<div class="single-info">
<span>Length:</span>
<span>${movie.runtime} minutes</span>
</div>
<div class="single-info">
<span>Rate:</span>
<span>${movie.vote_average} / 10</span>
</div>
<div class="single-info">
<span>Budget:</span>
<span>$ ${movie.budget}</span>
</div>
<div class="single-info">
<span>Release Date:</span>
<span>${movie.release_date}</span>
</div>
</div>
<div class="genres">
<h2>Genres</h2>
<ul>
${movie.genres.map(e => `<li>${e.name}</li>`).join('')}
</ul>
</div>
<div class="overview">
<h2>Overview</h2>
<p>${movie.overview}</p>
</div>
<div class="trailer">
<h2>Trailer</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/${movie_trailer}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
</div>
</div>
`
const x_icon = document.querySelector('.x-icon')
x_icon.addEventListener('click', () => popup_container.classList.remove('show-popup'))
const heart_icon = popup_container.querySelector('.heart-icon')
const movie_ids = get_LS()
for(let i = 0; i <= movie_ids.length; i++) {
if (movie_ids[i] == movie_id) heart_icon.classList.add('change-color')
}
heart_icon.addEventListener('click', () => {
if(heart_icon.classList.contains('change-color')) {
remove_LS(movie_id)
heart_icon.classList.remove('change-color')
} else {
add_to_LS(movie_id)
heart_icon.classList.add('change-color')
}
fetch_favorite_movies()
})
}
// Local Storage
function get_LS () {
const movie_ids = JSON.parse(localStorage.getItem('movie-id'))
return movie_ids === null ? [] : movie_ids
}
function add_to_LS (id) {
const movie_ids = get_LS()
localStorage.setItem('movie-id', JSON.stringify([...movie_ids, id]))
}
function remove_LS (id) {
const movie_ids = get_LS()
localStorage.setItem('movie-id', JSON.stringify(movie_ids.filter(e => e !== id)))
}
// Favorite Movies
fetch_favorite_movies()
async function fetch_favorite_movies () {
main_grid.innerHTML = ''
const movies_LS = await get_LS()
const movies = []
for(let i = 0; i <= movies_LS.length - 1; i++) {
const movie_id = movies_LS[i]
let movie = await get_movie_by_id(movie_id)
add_favorites_to_dom_from_LS(movie)
movies.push(movie)
}
}
function add_favorites_to_dom_from_LS (movie_data) {
main_grid.innerHTML += `
<div class="card" data-id="${movie_data.id}">
<div class="img">
<img src="${image_path + movie_data.poster_path}">
</div>
<div class="info">
<h2>${movie_data.title}</h2>
<div class="single-info">
<span>Rate: </span>
<span>${movie_data.vote_average} / 10</span>
</div>
<div class="single-info">
<span>Release Date: </span>
<span>${movie_data.release_date}</span>
</div>
</div>
</div>
`
const cards = document.querySelectorAll('.card')
add_click_effect_to_card(cards)
}
// Trending Movies
get_trending_movies()
async function get_trending_movies () {
const resp = await fetch(`https://api.themoviedb.org/3/trending/all/day?api_key=${API_KEY}`)
const respData = await resp.json()
return respData.results
}
add_to_dom_trending()
async function add_to_dom_trending () {
const data = await get_trending_movies()
console.log(data);
trending_el.innerHTML = data.slice(0, 5).map(e => {
return `
<div class="card" data-id="${e.id}">
<div class="img">
<img src="${image_path + e.poster_path}">
</div>
<div class="info">
<h2>${e.title}</h2>
<div class="single-info">
<span>Rate: </span>
<span>${e.vote_average} / 10</span>
</div>
<div class="single-info">
<span>Release Date: </span>
<span>${e.release_date}</span>
</div>
</div>
</div>
`
}).join('')
}
So After Copy Paste Work, This is How Your Website Will Look Like:
So this Was It For this Blog See You In the Next One Till Then Keep Coding Keep Exploring!
- The JS Developer’s Podcast [EP: 2] Variables and Data Manipulation - October 15, 2024
- YouTube Channels to Learn Coding: Top 9 Picks That Will Make a You Master - October 10, 2024
- The JS Developer’s Podcast [EP: 1] Introduction to JavaScript - September 27, 2024
great publish,very informative. I wonder whʏ the opposite experts ᧐f this sector do not realize
this. Уօu must proceed your writing. Ι’m suге, you have a
grfeat readers’ bas ɑlready!
Hi there, I do believe your website may be having browser compatibility problems.
Whenever I look at your blog in Safari, it looks fine however, if opening in I.E., it
has some overlapping issues. I simply wanted to give you a quick heads up!
Other than that, great blog!
Ok Our Team Will Fix It Soon! BTW Thanks