diff --git a/index.html b/index.html new file mode 100644 index 00000000..87bf71d7 --- /dev/null +++ b/index.html @@ -0,0 +1,51 @@ + + + + + + Project Cinema + + + + +
+

OMDb Movie search

+
+
+ +
    +
+ + + +
+
+
+

+
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/src/css/style.css b/src/css/style.css new file mode 100644 index 00000000..9decf827 --- /dev/null +++ b/src/css/style.css @@ -0,0 +1,209 @@ +/* font-family: 'Source Sans Pro', sans-serif; */ +@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro"); + +:root { + --primary-color: #f1f1f1; + --secondary-color: #fdb813; +} + +body { + font-family: "Source Sans Pro", sans-serif; + margin: 0; + padding: 0; + font-size: 16px; +} +.container { + width: 100%; + max-width: 100%; +} + +h1.main-heading { + padding-left: 30px; +} + +@media (min-width: 768px) { + h1.main-heading { + padding-left: 0; + } +} + +/* Search form */ +.search-form { + /* margin-bottom: 60px; */ + background-color: var(--primary-color); + padding: 30px; +} + +@media (min-width: 768px) { + .container { + width: 80%; + max-width: 1200px; + margin: 0 auto; + } +} + +.movie-request__form { + display: block; + position: relative; +} +@media (min-width: 768px) { + .movie-request__form { + display: flex; + flex-wrap: wrap; + } +} + +.search-form input.movie-request__input { + width: calc(100% - 36px); + padding: 15px; + font-size: 1.1rem; + color: var(--secondary-color); +} + +.movie-request__submit { + width: 100%; + padding: 20px; + border: none; + background-color: var(--secondary-color); + color: #fff; + font-size: 0.875rem; +} + +@media (min-width: 768px) { + .movie-request__submit { + width: 100px; + } + .search-form input.movie-request__input { + width: calc(100% - 140px); + } +} + +/* Autocomplete */ +.autocomplete { + width: calc(100% - 25px); + position: absolute; + top: 58px; + background-color: #fff; + margin: 0; + left: 1px; + list-style-type: none; + padding-left: 20px; +} +.autocomplete li { + line-height: 30px; +} +.autocomplete li:hover { + color: #666; + cursor: pointer; +} + +/* Search filters */ +.movie-request__filters-list { + width: 100%; + margin-top: 10px; + padding-left: 9px; +} +.movie-request__filters-list.hidden { + display: none; +} +.movie-request__filters-list select { + margin-right: 10px; +} +.movie-request__filters-list label { + font-size: 0.875rem; +} + +.movie-request__filters-toggle { + border: none; + background-color: transparent; + margin-top: 10px; + font-size: 0.875rem; +} + +.movie-request__filters-toggle:hover { + cursor: pointer; + opacity: 0.7; +} + +/* Movies list */ +.movie-list-wrapper { + display: grid; + grid-template-columns: 100%; + padding: 30px; + margin-bottom: 30px; + background-color: var(--primary-color); +} +@media (min-width: 480px) { + .movie-list-wrapper { + grid-template-columns: 200px auto; + } +} + +.movie-info__moreinfo { + display: block; + margin-top: 10px; + margin-bottom: 10px; + width: 100px; + height: 40px; + border: none; + background-color: var(--secondary-color); + color: #fff; + font-size: 0.875rem; +} + +.movie-info__title { + border-bottom: 2px solid var(--secondary-color); +} +.movie-info__imdb-link { + display: block; + color: #000; +} + +.movie-poster img { + width: 100%; + max-width: 100%; +} + +@media (min-width: 480px) { + .movie-poster img { + width: 100%; + max-width: 150px; + } +} + +/* Movie more info details */ +ul.movie-info__moreinfo-details { + list-style-type: none; + padding-left: 0; +} + +/* Errors */ +.error-box { + display: none; + width: calc(100% - 44px); + color: #fff; + background-color: tomato; + padding: 10px 20px; +} + +/* Pagination */ +.pagination { + list-style-type: none; + visibility: hidden; + display: flex; + justify-content: flex-end; + width: 100%; + padding-left: 0; +} + +.pagination-index { + margin: 0 20px; +} + +/* .pagination li { +} */ + +.pagination li:hover { + cursor: pointer; + opacity: 0.7; +} diff --git a/src/js/index.js b/src/js/index.js new file mode 100644 index 00000000..c38deca1 --- /dev/null +++ b/src/js/index.js @@ -0,0 +1,260 @@ +const OMBbAPIKey = "aba7af8e"; +const form = document.querySelector("#movie-request__form"); +const searchInput = form.querySelector("#movie-request__input"); +const resultsPlaceholder = document.querySelector("#search-results"); +const pagination = document.querySelector("#pagination"); +const paginationIndex = pagination.querySelector("#pagination-index"); +const nextPage = pagination.querySelector("#next-page"); +const prevPage = pagination.querySelector("#prev-page"); +const autocompleteList = document.querySelector("#autocomplete"); +let page = 1; + +// Results pagination +// @param {number} Next page to go +// @parem {number} Total search results +function paginate(page, totalResults) { + const totalPages = Math.ceil(totalResults / 10); + if (totalResults > 10) { + pagination.setAttribute("style", "visibility:visible"); + paginationIndex.innerHTML = ` ${page}/${totalPages} `; + if (page <= 1) { + prevPage.setAttribute("style", "visibility:hidden"); + nextPage.setAttribute("style", "visibility:visible"); + } else if (page > 1 && page !== totalPages) { + prevPage.setAttribute("style", "visibility:visible"); + nextPage.setAttribute("style", "visibility:visible"); + } else if (page === totalPages) { + prevPage.setAttribute("style", "visibility:visible"); + nextPage.setAttribute("style", "visibility:hidden"); + } + } else { + prevPage.setAttribute("style", "visibility:hidden"); + } +} + +// Movie list fetch +// @param {string} Terms to search +// @parem {number} Next page to go +function movieListFetch(searchInput, pageToGo, type = "", year = "") { + fetch( + `http://www.omdbapi.com/?s=${searchInput}&apikey=${OMBbAPIKey}&y=${year}&t=${type}&page=${pageToGo}` + ) + .then(response => response.json()) + .then(data => { + // Pagination + paginate(pageToGo, data.totalResults); + page = page + 1; + + // Movie markup for every search result + const movieData = data.Search; + const movieMarkup = ` + ${movieData + .map( + movie => + ` +
+
+ +
+
+

${movie.Title}

+
Year: ${ + movie.Year + }
+ IMDb ↗ + +
+
+ ` + ) + .join("")} + `; + resultsPlaceholder.innerHTML = movieMarkup; + }) + .catch(error => { + errorDisplay("Nothing found."); + // console.error(error); + }); +} + +// Title details fetch +// @param {string} Movie title +// @param {Object} event object +function movieFetch(title, e) { + const movieParentNode = e.target.parentNode; + const movieInfoWrapper = document.querySelector("movie-info"); + fetch(`http://www.omdbapi.com/?t=${title}&apikey=${OMBbAPIKey}`) + .then(response => { + // console.warn(response); + return response.json(); + }) + .then(data => { + // Show/hide the list + if (movieParentNode.querySelector(".movie-info__moreinfo-details")) { + // Remove list + movieParentNode.querySelector(".movie-info__moreinfo-details").remove(); + // Update button text + e.target.textContent = "More Info"; + } else { + // Create list with movie details + const infoToDisplay = [ + "Genre", + "Plot", + "Runtime", + "Awards", + "Language" + ]; + const html = Object.keys(data) + .map(function(key) { + if (infoToDisplay.indexOf(key) !== -1) { + return `
  • ${key}: ${data[key]}
  • `; + } + }) + .join(""); + + // Update button text + e.target.textContent = "Close"; + + // Append list + const moreInfoList = document.createElement("ul"); + moreInfoList.setAttribute("class", "movie-info__moreinfo-details"); + moreInfoList.innerHTML = html; + movieParentNode.append(moreInfoList); + } + }) + .catch(error => { + console.error(error); + // debugger; + }); +} + +// Autocomplete fetch +// @param {string} Movie title +// @param {Object} event object +function searchAutocomplete(title, e) { + const autocompleteList = document.querySelector("#autocomplete"); + fetch(`http://www.omdbapi.com/?s=${title}&apikey=${OMBbAPIKey}`) + .then(response => { + // console.warn(response); + return response.json(); + }) + .then(data => { + const html = data.Search.map(movie => { + return `
  • ${movie.Title}
  • `; + }).join(""); + + // Append list + autocompleteList.innerHTML = html; + }) + .catch(error => { + autocompleteList.innerHTML = "
  • No matches found
  • "; + // console.error(error); + // debugger; + }); +} + +// Error display box +// @param {string} Error message to display +function errorDisplay(msg) { + const errorBox = document.querySelector("#error-box"); + errorBox.textContent = msg; + errorBox.setAttribute("style", "display:block"); + setTimeout(function() { + errorBox.setAttribute("style", "display:none"); + }, 5000); +} + +// Generate year filter select options +function yearsDropdown() { + let yearsHTML = ['']; + for (let i = new Date().getFullYear(); i > 1900; i -= 1) { + yearsHTML.push(``); + } + document.querySelector( + "#movie-request__filters-year" + ).innerHTML = yearsHTML.join(""); +} + +// Form submit event handler +form.addEventListener("submit", function(e) { + const type = document.querySelector("#movie-request__filters-type").value; + const year = document.querySelector("#movie-request__filters-year").value; + + e.preventDefault(); + // Reset pagination + page = 1; + pagination.setAttribute("style", "visibility:hidden"); + + // Fetch results + movieListFetch(searchInput.value, page, type, year); + + // Clear autocomplete list after submit + autocompleteList.innerHTML = ""; +}); + +// Form input/change event handler +form.addEventListener("input", function(e) { + const autocomplete = document.querySelector("#autocomplete"); + if (e.target.id == "movie-request__input") { + page = 1; + pagination.setAttribute("style", "visibility:hidden"); + if (searchInput.value.length > 3) { + // Fetch results + searchAutocomplete(searchInput.value, page); + } + } +}); +// form.addEventListener("change", function(e) { +// autocompleteList.innerHTML = ""; +// }); + +form.addEventListener("click", function(e) { + // console.log(e.target.className); + if (e.target.className == "autocomplete-item") { + // console.log(e.target.innerText); + searchInput.value = e.target.innerText; + // Reset pagination + page = 1; + pagination.setAttribute("style", "visibility:hidden"); + + // Clear autocomplete list + autocompleteList.innerHTML = ""; + + // Fetch results + movieListFetch(e.target.innerText, page); + } +}); + +// Form filters toggle event handler +form.addEventListener("click", function(e) { + if (e.target.id == "movie-request__filters-toggle") { + const filters = document.querySelector("#movie-request__filters-list"); + filters.classList.toggle("hidden"); + yearsDropdown(); + } +}); + +// More info button event handler +resultsPlaceholder.addEventListener("click", function(e) { + if (e.target.id == "movie-info__moreinfo") { + movieFetch(e.target.attributes["data-title"].value, e); + } +}); + +// Pagination event handlers +nextPage.addEventListener("click", function() { + movieListFetch(searchInput.value, page); +}); +prevPage.addEventListener("click", function() { + movieListFetch(searchInput.value, page - 2); + page = page - 2; +});