forked from AsmrProg-YT/100-days-of-javascript
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8ef73b4
commit 68350a0
Showing
6 changed files
with
323 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Day #38 | ||
|
||
### Movie App (TheMovieDB) | ||
In this tutorial ([Open in Youtube](https://youtu.be/dButm3gpZDA)), I am gonna showing to you how to code a Movie App using JavaScript. in this video i'm using TheMovieDB api to get movies info. Also this code is fully responsive and when you scroll it will load more results❗️ | ||
|
||
## Warning | ||
You need to get your own api key (in video we showed how!) and replace it in index.js file on line 1 : | ||
|
||
```javascript | ||
const apiKey = "YOUR_API_KEY"; | ||
``` | ||
|
||
|
||
# Screenshot | ||
Here we have project screenshot : | ||
|
||
![screenshot](screenshot.jpg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<link rel="stylesheet" href="style.css"> | ||
<title>Day #38 - Movie App | AsmrProg</title> | ||
</head> | ||
|
||
<body> | ||
|
||
<div class="container"> | ||
<div class="search-box"> | ||
<a href="#"> | ||
<h1>MovieDB Api</h1> | ||
</a> | ||
<form id="search-form"> | ||
<input type="text" id="search-input" placeholder="Search Movies ..."> | ||
<button class="search-btn" type="submit">Search</button> | ||
</form> | ||
</div> | ||
|
||
<div id="result"></div> | ||
|
||
</div> | ||
|
||
<script src="index.js"></script> | ||
|
||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
const apiKey = "YOUR_API_KEY"; | ||
const imgApi = "https://image.tmdb.org/t/p/w1280"; | ||
const searchUrl = `https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&query=`; | ||
const form = document.getElementById("search-form"); | ||
const query = document.getElementById("search-input"); | ||
const result = document.getElementById("result"); | ||
|
||
let page = 1; | ||
let isSearching = false; | ||
|
||
// Fetch JSON data from url | ||
async function fetchData(url) { | ||
try { | ||
const response = await fetch(url); | ||
if (!response.ok) { | ||
throw new Error("Network response was not ok."); | ||
} | ||
return await response.json(); | ||
} catch (error) { | ||
return null; | ||
} | ||
} | ||
|
||
// Fetch and show results based on url | ||
async function fetchAndShowResult(url) { | ||
const data = await fetchData(url); | ||
if (data && data.results) { | ||
showResults(data.results); | ||
} | ||
} | ||
|
||
// Create movie card html template | ||
function createMovieCard(movie) { | ||
const { poster_path, original_title, release_date, overview } = movie; | ||
const imagePath = poster_path ? imgApi + poster_path : "./img-01.jpeg"; | ||
const truncatedTitle = original_title.length > 15 ? original_title.slice(0, 15) + "..." : original_title; | ||
const formattedDate = release_date || "No release date"; | ||
const cardTemplate = ` | ||
<div class="column"> | ||
<div class="card"> | ||
<a class="card-media" href="./img-01.jpeg"> | ||
<img src="${imagePath}" alt="${original_title}" width="100%" /> | ||
</a> | ||
<div class="card-content"> | ||
<div class="card-header"> | ||
<div class="left-content"> | ||
<h3 style="font-weight: 600">${truncatedTitle}</h3> | ||
<span style="color: #12efec">${formattedDate}</span> | ||
</div> | ||
<div class="right-content"> | ||
<a href="${imagePath}" target="_blank" class="card-btn">See Cover</a> | ||
</div> | ||
</div> | ||
<div class="info"> | ||
${overview || "No overview yet..."} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
`; | ||
return cardTemplate; | ||
} | ||
|
||
// Clear result element for search | ||
function clearResults() { | ||
result.innerHTML = ""; | ||
} | ||
|
||
// Show results in page | ||
function showResults(item) { | ||
const newContent = item.map(createMovieCard).join(""); | ||
result.innerHTML += newContent || "<p>No results found.</p>"; | ||
} | ||
|
||
// Load more results | ||
async function loadMoreResults() { | ||
if (isSearching) { | ||
return; | ||
} | ||
page++; | ||
const searchTerm = query.value; | ||
const url = searchTerm ? `${searchUrl}${searchTerm}&page=${page}` : `https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${apiKey}&page=${page}`; | ||
await fetchAndShowResult(url); | ||
} | ||
|
||
// Detect end of page and load more results | ||
function detectEnd() { | ||
const { scrollTop, clientHeight, scrollHeight } = document.documentElement; | ||
if (scrollTop + clientHeight >= scrollHeight - 20) { | ||
loadMoreResults(); | ||
} | ||
} | ||
|
||
// Handle search | ||
async function handleSearch(e) { | ||
e.preventDefault(); | ||
const searchTerm = query.value.trim(); | ||
if (searchTerm) { | ||
isSearching = true; | ||
clearResults(); | ||
const newUrl = `${searchUrl}${searchTerm}&page=${page}`; | ||
await fetchAndShowResult(newUrl); | ||
query.value = ""; | ||
} | ||
} | ||
|
||
// Event listeners | ||
form.addEventListener('submit', handleSearch); | ||
window.addEventListener('scroll', detectEnd); | ||
window.addEventListener('resize', detectEnd); | ||
|
||
// Initialize the page | ||
async function init() { | ||
clearResults(); | ||
const url = `https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${apiKey}&page=${page}`; | ||
isSearching = false; | ||
await fetchAndShowResult(url); | ||
} | ||
|
||
init(); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&display=swap'); | ||
|
||
*{ | ||
margin: 0; | ||
outline: none; | ||
font-family: 'Poppins', sans-serif; | ||
box-sizing: border-box; | ||
} | ||
|
||
a{ | ||
color: #fff; | ||
text-decoration: none; | ||
} | ||
|
||
body{ | ||
color: #fff; | ||
background-color: #212121; | ||
padding: 1.5rem; | ||
} | ||
|
||
.search-box{ | ||
width: 100%; | ||
display: flex; | ||
justify-content: space-between; | ||
flex-wrap: wrap; | ||
max-width: 1200px; | ||
align-items: center; | ||
margin: 15px 0 30px 0; | ||
} | ||
|
||
.search-box form{ | ||
display: flex; | ||
max-width: 400px; | ||
} | ||
|
||
.search-box input{ | ||
width: 100%; | ||
max-width: 400px; | ||
padding: 8px; | ||
border-radius: 0.4rem 0 0 0.4rem; | ||
border: none; | ||
background-color: rgba(255, 255, 255, 0.9); | ||
} | ||
|
||
.search-box .search-btn{ | ||
width: 120px; | ||
background-color: #01579b; | ||
color: #fff; | ||
cursor: pointer; | ||
padding: 6px 8px; | ||
border: 1px solid rgba(255, 255, 255, 0.5); | ||
border-radius: 0 0.4rem 0.4rem 0; | ||
transition: all 0.5s ease; | ||
} | ||
|
||
.search-box .search-btn:hover{ | ||
background-color: #0091ea; | ||
border: 1px solid #fff; | ||
} | ||
|
||
.container{ | ||
width: 100%; | ||
max-height: 100vh; | ||
display: flex; | ||
align-items: center; | ||
flex-direction: column; | ||
} | ||
|
||
.container .card{ | ||
position: relative; | ||
font-size: 14px; | ||
border: 1px solid rgba(255, 255, 255, 0.6); | ||
border-radius: 0.4rem; | ||
line-height: 20px; | ||
width: 285px; | ||
height: 360px; | ||
overflow: hidden; | ||
transition: all 0.5s ease; | ||
} | ||
|
||
.container .card .card-content{ | ||
width: 100%; | ||
position: absolute; | ||
bottom: 0; | ||
left: 0; | ||
padding: 100px 10px 5px; | ||
background-image: linear-gradient(180deg, rgba(51, 55, 69, 0), rgba(16, 21, 40, 0.95)); | ||
transition: all 0.5s ease; | ||
} | ||
|
||
.container .card .card-content .card-header{ | ||
padding: 8px 0; | ||
display: flex; | ||
align-items: center; | ||
justify-content: space-between; | ||
} | ||
|
||
.container .card .card-content .card-btn{ | ||
color: #fff; | ||
cursor: pointer; | ||
padding: 6px 8px; | ||
border: 1px solid rgba(255, 255, 255, 0.5); | ||
border-radius: 0.4rem; | ||
transition: all 0.5s ease; | ||
} | ||
|
||
.container .card .card-content .info{ | ||
max-height: 0; | ||
opacity: 0; | ||
border-top: 1px solid rgba(255, 255, 255, 0.3); | ||
overflow: hidden; | ||
transition: all 0.5s ease; | ||
} | ||
|
||
.container .card:hover{ | ||
cursor: pointer; | ||
} | ||
|
||
.container .card:hover .card-content{ | ||
background-image: linear-gradient(180deg, rgba(51, 55, 69, 0), #101528 48%); | ||
} | ||
|
||
.container .card:hover .card-btn{ | ||
background-color: #0091ea; | ||
border-color: #0091ea; | ||
} | ||
|
||
.container .card:hover .info{ | ||
max-height: 200px; | ||
opacity: 1; | ||
padding: 8px 0; | ||
} | ||
|
||
#result{ | ||
display: flex; | ||
max-width: 1200px; | ||
gap: 15px; | ||
flex-direction: row; | ||
flex-wrap: wrap; | ||
justify-content: center; | ||
} | ||
|
||
@media screen and (max-width: 550px) { | ||
.search-box{ | ||
justify-content: center; | ||
} | ||
|
||
.search-box form{ | ||
margin-top: 10px; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters