diff --git a/README.md b/README.md index 49093dd2..0343c7ca 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,80 @@ # Project Cinema -We want to create a movie search engine. To power it we will use the [Open Movie Database](http://www.omdbapi.com) API. +> # A movie search engine powered by the [Open Movie Database](http://www.omdbapi.com) API. +> +> ## _”A mobile-first, responsive design that looks great at different screen widths“_ -To start using the OMDB API you will first need to sign up with them to receive and API key. The key issued to you will allow you 1000 requests per day and you will need to include this key as part of every request. +--- -To get started, fork and clone this repo. Please submit a pull request after your first commit and push commits regularly. +--- -You should complete as many of the following tasks as you can. +## UX -- [ ] Work using mobile first, that is create the mobile version first and add tablet and desktop versions after. -- [ ] Create an HTML page which should have a `form` at the top which contains a text input and a submit button. Below it should have a placeholder element for the returned results. -- [ ] Use JavaScript to capture the `submit` event in your search form, extract the query string from the text input and use that to make an API call to the Open Movie Database API to search for films which match the query string using `fetch`. `console.log` the results -- [ ] Display the data returned by the API including title, year and poster picture +- Type in your search query and hit the button. -**Movie details** +![image](https://user-images.githubusercontent.com/42837452/45933010-84862080-bf7d-11e8-8881-aa7b004c2dcf.png) -- [ ] Adjust your layout to create room for a detailed view of movie information -- [ ] Capture clicks on your movie results items and use that information to make another request to the API for detailed movie information. Using event delegation will help you here. `console.log` the returned result -- [ ] Display the detailed movie result in the in the details view you created earlier -- [ ] Make your design responsive and ensure it looks great at different screen widths +- Search results are loaded below and the screen scrolls up automatically. -**Your own feature** +- Load more search results by paging through. You get 10 results at a time. -- [ ] Implement any feature you would find useful or interesting +![image](https://user-images.githubusercontent.com/42837452/45933027-9e276800-bf7d-11e8-80c0-974186b510bc.png) -**Stretch goals** +- Just tap on any of the films in the search results to see more information. This loads below the search results and the screen scrolls up automatically. -- [ ] Implement pagination so that users can navigate between all movies in search results rather than just the first ten -- [ ] Create a favourites list. It's up to you how you would add items to favourites. You could add a button or otherwise. Display a list of favourites somewhere on your page. -- [ ] Make the favourites list sortable. Add `up` and `down` buttons to your favourites which on click will move the result in relevant direction -- [ ] Save favourites locally using `localStorage` so that favourites persist in browser after refresh -- [ ] Let's create a search preview. It should listen for change events on input events and submit a search request with current query string. Display the search preview results in an absolute positioned container just below the search box. -Hint: You may want to kick of the searching after at least 3 characters have been typed. +![image](https://user-images.githubusercontent.com/42837452/45933033-b303fb80-bf7d-11e8-8ec7-90c321be83a9.png) -## Objectives +- Save your favourite films - just click the button on the film detail view. -* We want to see great looking webpages that work well at all screen widths -* Your code should have consistent indentation and sensible naming -* Use lots of concise, reusable functions with a clear purpose -* Add code comments where it is not immediately obvious what your code does -* Your code should not throw errors and handle edge cases gracefully. For example not break if server fails to return expected results -* Use BEM methodology to style your page -* Try to use pure functions as much as possible, but keep in mind it will not be possible to make all functions pure. +![image](https://user-images.githubusercontent.com/42837452/45933039-c57e3500-bf7d-11e8-825b-aca38431774d.png) -## README.md +- You can see your list of favourites by clicking the account button in the header. You can delete films from the list individually or delete them all with a single click. -When finished, include a README.md in your repo. Someone who is not familiar with the project should be able to look at it and understand what it is and what to do with it. Explain functionality created, mention any outstanding issues and possible features you would include if you had more time. List technologies used to create the app. Include a screenshot of your app in the README. +![image](https://user-images.githubusercontent.com/42837452/45933045-daf35f00-bf7d-11e8-9e85-395d30f62476.png) + +## Technology used + +- **HTML & CSS** (Flexbox, Grid) + - BEM methodology used in markup and CSS. + - Individual media queries for tablet and desktop in separate files to make the styles easier to maintain. +- **JavaScript** (Fetch, OMDB API, localStorage) + - Functions are pure as much as possible – concise reusable and each with with a clear purpose. + - Well commented throughout. + +## Surprise feature + +- If the film you‘re looking for doesn't have a poster then look out for the ’Fill Ferrell‘ placeholder image. + +![image](https://user-images.githubusercontent.com/42837452/45933051-f52d3d00-bf7d-11e8-8c59-8465ca813676.png) + +--- + +## Challenges, learnings and TODOs + +- **localStorage** + + - Favourites currently stored individually in localStorage. + - Working with a database that stores strings of information is challenging. + - TODO: Need to refactor to store a single object in localStorage. On page load this can be retrieved and parsed. Stored in an object the user favourites can then be manipulated and updated. On any interaction even the object can be stringified before re-setting in localStorage. + - [ ] TODO: Make the favourites list sortable. Add `up` and `down` buttons to your favourites which on click will move the result in relevant direction. Also sortable by date saved and film title. + - [ ] TODO: Implement a watch list feature to save films that you want to see as well as favourites. + +- **Search** + + - [ ] TODO: Create a search preview. It should listen for change events on input events and submit a search request with current query string. Display the search preview results in an absolute positioned container just below the search box. Kick of the searching after at least 3 characters have been typed. + +- **Refactoring** + + - [ ] TODO: Refactor code to make use of export/import to keep JS easy to navigate and maintain. + +--- + +### The original brief + +- We want to see great looking webpages that work well at all screen widths +- Your code should have consistent indentation and sensible naming +- Use lots of concise, reusable functions with a clear purpose +- Add code comments where it is not immediately obvious what your code does +- Your code should not throw errors and handle edge cases gracefully. For example not break if server fails to return expected results +- Use BEM methodology in your markup and CSS to style your page +- Try to use pure functions as much as possible, but keep in mind it will not be possible to make all functions pure. diff --git a/index.html b/index.html new file mode 100644 index 00000000..98a03af6 --- /dev/null +++ b/index.html @@ -0,0 +1,46 @@ + + + + + + + + The Reel Thing - Find Your Favourite Films + + + + + + + + + +
+
+

The Reel Thing

+ +
+ +
+
+

Your favourites

+
    +
    +
    + + +
    + +
    +
    + + + + \ No newline at end of file diff --git a/src/bg_popcorn.jpg b/src/bg_popcorn.jpg new file mode 100644 index 00000000..d4c4fa7c Binary files /dev/null and b/src/bg_popcorn.jpg differ diff --git a/src/data.json b/src/data.json new file mode 100644 index 00000000..1cd2fc36 --- /dev/null +++ b/src/data.json @@ -0,0 +1,93 @@ +HTTP/1.1 200 OK +Date: Sun, 23 Sep 2018 07:24:17 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Cache-Control: public, max-age=86400 +Expires: Mon, 24 Sep 2018 07:24:17 GMT +Last-Modified: Sat, 22 Sep 2018 15:18:36 GMT +Vary: *, Accept-Encoding +X-AspNet-Version: 4.0.30319 +X-Powered-By: ASP.NET +Access-Control-Allow-Origin: * +CF-Cache-Status: HIT +Server: cloudflare +CF-RAY: 45eb4552917f0a7e-LHR +Content-Encoding: gzip + +{ + "Search": [ + { + "Title": "Titanic", + "Year": "1997", + "imdbID": "tt0120338", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMDdmZGU3NDQtY2E5My00ZTliLWIzOTUtMTY4ZGI1YjdiNjk3XkEyXkFqcGdeQXVyNTA4NzY1MzY@._V1_SX300.jpg" + }, + { + "Title": "Titanic II", + "Year": "2010", + "imdbID": "tt1640571", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMTMxMjQ1MjA5Ml5BMl5BanBnXkFtZTcwNjIzNjg1Mw@@._V1_SX300.jpg" + }, + { + "Title": "Titanic: The Legend Goes On...", + "Year": "2000", + "imdbID": "tt0330994", + "Type": "movie", + "Poster": "https://ia.media-imdb.com/images/M/MV5BMTg5MjcxODAwMV5BMl5BanBnXkFtZTcwMTk4OTMwMg@@._V1_SX300.jpg" + }, + { + "Title": "Titanic", + "Year": "1953", + "imdbID": "tt0046435", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BMTU3NTUyMTc3Nl5BMl5BanBnXkFtZTgwOTA2MDE3MTE@._V1_SX300.jpg" + }, + { + "Title": "Titanic", + "Year": "1996", + "imdbID": "tt0115392", + "Type": "series", + "Poster": "https://m.media-amazon.com/images/M/MV5BMTIyNjc0NjgyMl5BMl5BanBnXkFtZTcwMDAzMTAzMQ@@._V1_SX300.jpg" + }, + { + "Title": "Raise the Titanic", + "Year": "1980", + "imdbID": "tt0081400", + "Type": "movie", + "Poster": "https://m.media-amazon.com/images/M/MV5BM2MyZWYzOTQtMTYzNC00OWIyLWE2NWItMzMwODA0OGQ2ZTRkXkEyXkFqcGdeQXVyMjI4MjA5MzA@._V1_SX300.jpg" + }, + { + "Title": "The Legend of the Titanic", + "Year": "1999", + "imdbID": "tt1623780", + "Type": "movie", + "Poster": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjMxNDU5MTk1MV5BMl5BanBnXkFtZTgwMDk5NDUyMTE@._V1_SX300.jpg" + }, + { + "Title": "Titanic", + "Year": "2012–", + "imdbID": "tt1869152", + "Type": "series", + "Poster": "https://m.media-amazon.com/images/M/MV5BMTcxNzYxOTAwMF5BMl5BanBnXkFtZTcwNzU3Mjc2Nw@@._V1_SX300.jpg" + }, + { + "Title": "Titanic: Blood and Steel", + "Year": "2012–", + "imdbID": "tt1695366", + "Type": "series", + "Poster": "https://m.media-amazon.com/images/M/MV5BMjI2MzU2NzEzN15BMl5BanBnXkFtZTcwMzI5NTU3Nw@@._V1_SX300.jpg" + }, + { + "Title": "In Search of the Titanic", + "Year": "2004", + "imdbID": "tt1719665", + "Type": "movie", + "Poster": "https://ia.media-imdb.com/images/M/MV5BMTAzNjY0NDA2NzdeQTJeQWpwZ15BbWU4MDIwMzc1MzEx._V1_SX300.jpg" + } + ], + "totalResults": "190", + "Response": "True" +} \ No newline at end of file diff --git a/src/desktop-style.css b/src/desktop-style.css new file mode 100644 index 00000000..b111fd93 --- /dev/null +++ b/src/desktop-style.css @@ -0,0 +1,160 @@ +@media (min-width: 1068px) { + header { + height: 8rem; + } + #title { + font-size: 4rem; + } + + .btn__account { + font-size: 4rem; + margin-right: 2rem; + } + + #account { + background: skyblue; + position: fixed; + top: -50rem; + left: 80vw; + width: 20vw; + z-index: 5; + transition: top 1s; + box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.5); + } + #account.account--active { + top: 8rem; + } + + .search__input { + width: 50vw; + font-size: 3rem; + font-weight: 400; + padding: 3rem; + } + + /* search results */ + .search-results__page { + width: 85vw; + margin: 0 auto; + padding: 1rem; + grid-template-columns: repeat(5, 20%); + justify-content: space-around; + } + + .film { + display: flex; + flex-direction: column; + flex: 1; + justify-self: center; + margin: 0 0.5rem; + width: 18vw; + } + + .film__title { + width: 13vw; + font-size: 1.3rem; + } + + .film__poster { + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.6); + width: 13vw; + height: 20vw; + border: 6px solid white; + object-fit: cover; + transition: all 0.5s; + } + + .film__poster:hover { + border-color: orangered; + } + + #page-nav { + font-size: 1.5rem; + justify-content: center; + background: whitesmoke; + } + + /*. film details */ + + #film-details { + background-image: url(/src/bg_popcorn.jpg); + background-size: cover; + padding: 5rem 0 1rem 0; + margin-bottom: 0; + } + + .film-details__wrapper { + width: 65vw; + margin: 0 auto; + padding-top: 1rem; + grid-template-columns: 22vw max-content 1fr; + grid-template-rows: repeat(5, min-content) 1fr; + } + + .film-details__title { + font-size: 2.3rem; + border-top: 5px solid black; + padding-top: 0.25rem; + width: 35vw; + } + + .btn__fav { + margin: 0 0.5rem 0.25rem; + font-size: 1.2rem; + justify-self: end; + align-self: start; + transition: padding 0.2s; + } + + .btn__fav:hover { + padding: 0.5rem 1rem; + } + + .film-details__poster { + grid-column: 1 / span 1; + grid-row: 1 / span 8; + width: 20vw; + justify-self: stretch; + border: none; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.6); + } + .film-details__wrapper h4 { + grid-column: 2 / span 2; + margin-bottom: 0.5rem; + align-self: end; + } + h4.film-details__director { + grid-column: 2 / span 2; + align-self: start; + margin-bottom: 0.25rem; + } + + .film-details__meta { + font-size: 1.2rem; + font-style: italic; + margin-top: 0.5rem; + grid-column: 2 / span 2; + } + + .film-details__plot, + .film-details__actors { + grid-column: 2 / span 2; + width: 30vw; + font-family: serif; + margin-top: 0; + font-size: 1rem; + } + + .film-details__ratings__imdb { + grid-column: 2 / span 2; + margin: 1rem 0; + font-size: 1.2rem; + } + + .film-details__wrapper h4 { + grid-column: 2 / span 2; + margin: 1rem 0 0.5rem 0; + align-self: end; + font-size: 1.4rem; + } +} diff --git a/src/fill-ferrell.jpg b/src/fill-ferrell.jpg new file mode 100644 index 00000000..cc746993 Binary files /dev/null and b/src/fill-ferrell.jpg differ diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..665a1987 --- /dev/null +++ b/src/index.js @@ -0,0 +1,313 @@ +import * as storage from './localStorage.js'; + +const myStorage = window.localStorage; + +console.log(window.innerWidth); + +window.scrollBy(0, -20); + +if (storage.storageAvailable('localStorage')) { + // localStorage.clear(); + console.log(`You’re all set to save your favourite films`); + console.log(myStorage); + console.log(window.innerHeight); +} else { + console.log('Please enable local storage to save your favourites.'); +} + +const params = { + base: 'http://www.omdbapi.com/?apikey=507b4100&type=movie', + pageNum: 1 +}; + +const setUrl = (paramsInit, query = '', id = '') => { + console.log(`${paramsInit.base}&page=${params.pageNum}&s=${query}&i=${id}`); + return `${paramsInit.base}&page=${ + params.pageNum + }&s=${query}&i=${id}&plot=full`; +}; + +const searchFilmBytitle = title => { + fetch(setUrl(params, title)) + .then(response => response.json()) + .then(body => displaySearchResults(body)) + .catch(error => { + if (films === undefined) { + alert('No films match your query, please search again'); + } else { + alert(error); + } + }); +}; + +const getFilmByID = id => { + fetch(setUrl(params, '', id)) + .then(response => response.json()) + .then(body => writeFilmDetails('#film-details', body)) + .catch(error => console.log(error)); +}; + +/* Search resutls */ + +const displaySearchResults = films => { + console.log(films); + const searchResults = createElement('div'); + searchResults.classList.add('search-results__page'); + searchResults.setAttribute('id', `page-${params.pageNum}`); + films.Search.forEach(film => { + const filmListing = createFilmSearchListing( + film.imdbID, + film.Title, + film.Year, + film.Poster + ); + addElementToParent(searchResults, filmListing); + }); + const searchResultsWrapper = document.querySelector('#search-results'); + searchResultsWrapper.innerHTML = ''; + + addElementToParent(searchResultsWrapper, searchResults); + const paginationButtons = createPagination(films); + console.log(paginationButtons); + addElementToParent(searchResultsWrapper, paginationButtons); + addPaginationControls(); + if (window.innerWidth > 1064) { + window.scrollBy({ top: window.innerHeight - 100, behaviour: 'smooth' }); + } else if (window.innerWidth > 767) { + window.scrollBy({ top: window.innerHeight, behaviour: 'smooth' }); + } else { + window.scrollBy({ top: window.innerHeight - 60, behaviour: 'smooth' }); + } +}; + +const createFilmSearchListing = (id, title, year, poster) => { + const filmListing = createArticle('film'); + + poster === 'N/A' ? (poster = './src/fill-ferrell.jpg') : poster; + filmListing.innerHTML = ` +

    ${title} (${year})

    `; + filmListing.setAttribute('data-ID', id); + + return filmListing; +}; + +const createArticle = (articleClass = '') => { + const article = document.createElement('article'); + article.classList.add(articleClass); + + return article; +}; + +const createPagination = data => { + const pagination = createElement('nav'); + const numPages = Math.ceil(Number(data.totalResults) / 10); + // document.querySelector('.page-total').textContent = numPages; + pagination.innerHTML = `