diff --git a/README.md b/README.md index cec0904..2fb717e 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,25 @@ -# React Cinema +# Moudly Lemons -Let's revisit our first project where we built a movie search engine using the Open Movie Database. This time we want to implement it using React. It should be a Single Page App, that is all the functionality should be on a single page, rather switch between multiple pages. +_Lemon-inspired title referencing my favourite movie reviewing website_ -Before starting to code produce a diagram using pen and paper of your application which shows both layout and a tree diagram of the components. +## A movie search engine powered by the Open Movie Database -What are some of the components you are going to need? Which components will fetch data and how will that data be displayed? Which components will store state and how will they pass data to other components? Which components should be re-used? Rather than re-implementing your previous solution again have a think about what you have learned in the past week and how you can apply it here. +Moudly Lemons is a single-page app built using React, powered by the [Open Movie Database](http://www.omdbapi.com) API, CSS mobile first, with tablet and desktop views. -You can start coding once your plan has been checked by a TA or instructor. +### How it works -## The brief +- The app first captures a search input and fetches data that matches the query from the OMDB API. +- It displays results returned in pages (10 results per page). +- Each movie shows a poster image, title and release date, each with a unique ID used to identify the movie when selected. +- Each time a movie is selected, a further API request is made to fetch additional details +- Additional details are displayed in a toggle-box - summary description, director, actors, genre etc -We want to create a movie search engine. To power it we will use the [Open Movie Database](http://www.omdbapi.com) API. +### Features -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. +- Each movie has a "lemon rating" that converts the IMDB rating into an array of lemons +- Pagination to navigate back and forth to the extent of the results +- Visual cue to indicate when the search input is not filled +- "Zombie" placeholders as fallback when no movie poster supplied +- Page scroll functionality for viewing additional details (applied in mobile view only) -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. - -- [ ] 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 - -**Movie details** - -- [ ] 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 - -**Your own feature** - -- [ ] Implement any feature you would find useful or interesting - -**Stretch goals** - -- [ ] 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 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. - -## Objectives - -* 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. - -## README.md - -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. +![Screenshot](./static/movie-screenshot-1.png) diff --git a/index.html b/index.html index 5956140..937abcd 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,22 @@ - + + + + - Hello World + Mouldy Lemons -
+
+

Mouldy Lemons

+

Discover the zestiest flicks

+
+
+ diff --git a/normalize.css b/normalize.css new file mode 100644 index 0000000..3d6624c --- /dev/null +++ b/normalize.css @@ -0,0 +1,341 @@ +/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8ca987c..1492620 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1915,6 +1915,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -2124,12 +2129,48 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "component-clone": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/component-clone/-/component-clone-0.2.2.tgz", + "integrity": "sha1-x/WXmCKID62M+wliuikYbQYe4E8=", + "requires": { + "component-type": "*" + } + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", "dev": true }, + "component-raf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/component-raf/-/component-raf-1.2.0.tgz", + "integrity": "sha1-srxy1D8bAU/eeks8RHx2S8c8y6o=" + }, + "component-tween": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/component-tween/-/component-tween-1.2.0.tgz", + "integrity": "sha1-zDnOXbqwW1KCX0HRlHY4oLAbK4o=", + "requires": { + "component-clone": "0.2.2", + "component-emitter": "1.2.0", + "component-type": "1.1.0", + "ease-component": "1.0.0" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.0.tgz", + "integrity": "sha1-zNETqGOI0GSC0D3j/H35hSa6jv4=" + } + } + }, + "component-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.1.0.tgz", + "integrity": "sha1-lbZmqtU+XI0fK+E1xFtdSZGXwMU=" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2485,6 +2526,11 @@ "stream-shift": "^1.0.0" } }, + "ease-component": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ease-component/-/ease-component-1.0.0.tgz", + "integrity": "sha1-s3VybbC1sEWVt3RAOW/sfapdd8k=" + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -4942,6 +4988,11 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, "log-symbols": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.1.0.tgz", @@ -6152,6 +6203,23 @@ "prop-types": "^15.6.0" } }, + "react-scroll": { + "version": "1.7.10", + "resolved": "https://registry.npmjs.org/react-scroll/-/react-scroll-1.7.10.tgz", + "integrity": "sha512-7K1caXF19PQ/jck+QRCdRMytqWei1ktv7jtcsgMap2s55pGOUc/a5phr4loajZRFRx3qKj9Tz12KDtELp91xMg==", + "requires": { + "lodash.throttle": "^4.1.1", + "prop-types": "^15.5.8" + } + }, + "react-scroll-to-component": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-scroll-to-component/-/react-scroll-to-component-1.0.2.tgz", + "integrity": "sha1-8mDck2xipT53J4bXgy/giE4ZU1Q=", + "requires": { + "scroll-to": "0.0.2" + } + }, "read-chunk": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", @@ -6544,6 +6612,15 @@ "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=", "dev": true }, + "scroll-to": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/scroll-to/-/scroll-to-0.0.2.tgz", + "integrity": "sha1-k205ipEzZgokkhRcLACB38sHKPM=", + "requires": { + "component-raf": "1.2.0", + "component-tween": "1.2.0" + } + }, "semver": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", diff --git a/package.json b/package.json index 26c045b..e6a7c4a 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,11 @@ ] }, "dependencies": { + "classnames": "^2.2.6", "react": "^16.2.0", - "react-dom": "^16.2.0" + "react-dom": "^16.2.0", + "react-scroll": "^1.7.10", + "react-scroll-to-component": "^1.0.2" }, "devDependencies": { "babel-loader": "^7.1.3", diff --git a/src/components/App.js b/src/components/App.js index 9520f77..c15f5b7 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,16 +1,81 @@ -import React from 'react'; +import React from "react"; +import Search from "./Search"; +import Movies from "./Movies"; +import Paging from "./Paging"; class App extends React.Component { - constructor(){ + constructor() { super(); + this.state = { + movieresults: [], + query: "", + page: 1, + noresults: "" + }; + this.receiveQuery = this.receiveQuery.bind(this); + this.receiveSubmit = this.receiveSubmit.bind(this); + this.receiveMovies = this.receiveMovies.bind(this); + this.receivePages = this.receivePages.bind(this); } - render(){ + fetchMovies() { + const moviesUrl = `http://www.omdbapi.com/?s=${this.state.query}&page=${ + this.state.page + }&apikey=eabbbb71`; + fetch(moviesUrl) + .then(response => response.json()) + .then(content => { + if (content.Response !== "False") { + this.setState({ + movieresults: content.Search, + moviestotal: content.totalResults + }); + } else { + this.setState({ noresults: "empty" }); + } + }); + } + + receiveQuery(query) { + this.setState({ query: query }); + } + receiveSubmit() { + this.fetchMovies(); + } + receiveResults() { + this.setState({ noresults: noresults }); + } + receiveMovies() { + this.setState({ movieresults: moviesresults }); + } + receivePages(num) { + // fetch movies when state is being set - not before + this.setState({ page: num }, () => this.fetchMovies()); + } + + render() { return ( -
- React cinema app -
- ) +
+ + +
+ +
+ + {this.state.movieresults.length !== 0 ? ( + + ) : null} +
+ ); } } diff --git a/src/components/Detail.js b/src/components/Detail.js new file mode 100644 index 0000000..8ea2b6f --- /dev/null +++ b/src/components/Detail.js @@ -0,0 +1,52 @@ +import React from "react"; + +class Detail extends React.Component { + constructor() { + super(); + } + + render() { + // Lemon rating - create array from IMDB rating + const rating = Array.from( + Array(Math.round(this.props.movie.imdbRating)).keys() + ); + // there is an issue with key duplication + + return ( +
+
+ + +

+ Lemon rating:{" "} + {rating.map(item => { + return ( + + ); + })} +

+
+
+ ); + } +} + +export default Detail; diff --git a/src/components/Movie.js b/src/components/Movie.js new file mode 100644 index 0000000..a7208ed --- /dev/null +++ b/src/components/Movie.js @@ -0,0 +1,96 @@ +import React from "react"; +import Detail from "./Detail"; +import cx from "classnames"; +import { scroller } from "react-scroll"; + +class Movie extends React.Component { + constructor() { + super(); + this.state = { clicked: false, movieresult: {} }; + this.handleClick = this.handleClick.bind(this); + this.scrollTo = this.scrollTo.bind(this); + } + + scrollTo() { + scroller.scrollTo(this.props.movie.imdbID, { + duration: 800, + delay: 0, + smooth: "easeInOutQuart" + }); + } + + handleClick(event) { + this.setState({ + clicked: !this.state.clicked + }); + + if (Math.max(window.innerWidth) < 768) { + this.scrollTo(); + } + } + + componentDidMount() { + const movieUrl = `http://www.omdbapi.com/?i=${ + this.props.movie.imdbID + }&apikey=eabbbb71`; + fetch(movieUrl) + .then(response => response.json()) + .then(content => { + this.setState({ movieresult: content }); + }); + } + + render() { + const articleclasses = cx("moviesfeed__article", { + active: this.state.clicked, + "": !this.state.clicked + }); + + const moviesfull = cx("moviesfeed__full", { + "details--open": this.state.clicked, + "details--closed": !this.state.clicked + }); + + const posterurl = + this.props.movie.Poster !== "N/A" + ? this.props.movie.Poster + : "https://placezombie.com/640x360"; + + return ( +
+
+
+
+

+ + {this.props.movie.Title} +    + {this.props.movie.Year} + +

+
+ + + {!this.state.clicked ? "Show details" : "Hide Details"} + +
+ + {this.state.clicked ? ( + + ) : null} +
+
+ ); + } +} + +export default Movie; diff --git a/src/components/Movies.js b/src/components/Movies.js new file mode 100644 index 0000000..e8653a1 --- /dev/null +++ b/src/components/Movies.js @@ -0,0 +1,16 @@ +import React from "react"; +import Movie from "./Movie"; + +class Movies extends React.Component { + render() { + return ( +
+ {this.props.movieresults.map(movie => { + return ; + })} +
+ ); + } +} + +export default Movies; diff --git a/src/components/Paging.js b/src/components/Paging.js new file mode 100644 index 0000000..741258f --- /dev/null +++ b/src/components/Paging.js @@ -0,0 +1,46 @@ +import React from "react"; + +class Paging extends React.Component { + constructor() { + super(); + this.state = { clicked: false, movieresult: {} }; + this.handleClickNext = this.handleClickNext.bind(this); + this.handleClickPrevious = this.handleClickPrevious.bind(this); + } + + handleClickNext(event) { + this.props.receivePages(this.props.currentPage + 1); + this.setState({ + clicked: !this.state.clicked + }); + } + handleClickPrevious(event) { + if (this.props.currentPage > 1) { + this.props.receivePages(this.props.currentPage - 1); + } + } + + render() { + const totalpages = this.props.totalresults / 10; + + return ( + + ); + } +} + +export default Paging; diff --git a/src/components/Search.js b/src/components/Search.js new file mode 100644 index 0000000..b4391bd --- /dev/null +++ b/src/components/Search.js @@ -0,0 +1,52 @@ +import React from "react"; +import cx from "classnames"; + +class Search extends React.Component { + constructor() { + super(); + this.state = { submitted: false }; + this.handleSubmit = this.handleSubmit.bind(this); + this.handleChange = this.handleChange.bind(this); + } + handleSubmit(event) { + event.preventDefault(); + this.props.receiveSubmit(); + this.setState({ + submitted: !this.state.submitted + }); + } + handleChange(event) { + this.props.receiveQuery(event.target.value); + } + + render() { + // when search not filled in - subtle hint + const searchInput = cx("search__input", { + "no--results": + this.state.submitted && + (this.props.noresults === "empty" || this.props.query === ""), + results: this.state.submitted && this.props.query !== "" + }); + + return ( +
+ +
+ ); + } +} + +export default Search; diff --git a/static/movie-screenshot-1.png b/static/movie-screenshot-1.png new file mode 100644 index 0000000..0120fc3 Binary files /dev/null and b/static/movie-screenshot-1.png differ diff --git a/style.css b/style.css index e69de29..775e9ff 100644 --- a/style.css +++ b/style.css @@ -0,0 +1,335 @@ +/** + * Notes BEM + * http://getbem.com/naming/ + */ + +/* Variables + ========= */ + + :root { + --main-txt-color: #0a0a0a; + --light-color: #EEE8CD; + --bright-color: #FFC220; + --dark-color: #2D363a; + + --main-padding: 1rem; +} + +/* ==== BASE ==== */ + +body { + font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif; + margin: 0; + padding: 0; + background: var(--dark-color); + line-height: 1.5; + color: var(--light-color); + -webkit-font-smoothing: antialiased; +} +.container { + padding-left: var(--main-padding); + padding-right: var(--main-padding); + margin: 0 auto; +} +.menu--settings { + list-style-type: none; + padding-left: 0; + padding-right: 0; + margin: 0; +} +img { +max-width: 100%; +height: auto; +border-style: none; +} + +/* ==== LINKS AND TYPOGRAPHY ==== */ +a { + text-decoration: none; + -webkit-transition: color 0.5s; + -moz-transition: color 0.5s; + transition: color 0.5s; + } + +/* ==== SEARCHFORM ==== */ + +.search__form { + width: 80%; + margin: 0 auto; +} +.search__input { + background: var(--light-color); + overflow: hidden; + white-space: nowrap; + padding: 0.35em 0; + text-align: center; + border: none; + font-size: 1.5rem; + text-decoration: none; + line-height: normal; + max-height: 3em; + width: 100%; +} +.no--results { + background: pink; +} +.search__btn { + background:var(--bright-color); + border: 1px solid var(--bright-color); + border-bottom-width: 0px; + text-transform: uppercase; + color: var(--dark-color); + padding: 0.35em 0.75em; + font-size: 1.5em; + text-decoration: none; + cursor: pointer; + width: 100%; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + transition: all 0.5s; +} +.search__btn:hover { + background: var(--main-txt-color); + color: var(--light-color); + border-color: var(--dark-color); +} +.search__input-wrapper { + position: relative +} +.search__preview { + position: absolute; + left: 0; + top: 3rem; + text-align: center; + width: 100%; + display: none; +} +.search__preview--show { + display: block; +} +.preview__item { + background:var(--light-color); + color: var(--dark-color); + padding: 0.35em 0.75em; + font-size: 1.25rem; + border-bottom: 1px dashed var(--dark-color); +} +.preview__item:last-child { + border-bottom: none; +} + + +/* ==== MAIN ==== */ + +.maincontent { + padding: var(--main-padding) 0; + margin-bottom: var(--main-padding); +} +.mainheader { + text-align: center; + padding: calc( 2.5 * var(--main-padding) ) 0 ; + border-bottom: 5px dashed var(--bright-color); + border-top: 5px dashed var(--bright-color); + margin-bottom: calc( 3 * var(--main-padding) ); + margin-top: 1px; +} +.mainheader__title, +.mainheader__subtitle { + margin: 0; +} +.search { + text-align: center; + margin-bottom: calc( 3 * var(--main-padding) ); +} +.moviesfeed article { + margin-bottom: calc( 4 * var(--main-padding) ); +} +.moviesfeed__full { + background-color: var(--main-txt-color); + background-repeat: no-repeat; + background-position: top center; + padding-top: 50%; + background-size: cover; + position: relative; +} +.moviesfeed__details { + background: var(--light-color); + color: var(--main-txt-color); + padding: var(--main-padding); +} +.movie__header { + position: absolute; + bottom: 0; + left: 0; + right: 0; + } +.movie__title { + margin: 0; + padding: calc( 1 * var(--main-padding) ); + background-color: rgba(0, 0, 0, 0.75); +} +.movie__title em { + color: var(--bright-color); +} + +.moviesfeed__btn { + position: absolute; + bottom: -40px; + left: 0; + right: 0; + height: 30px; + line-height: 30px; + text-align: center; + padding: 5px; + text-transform: uppercase; + background-color: var(--bright-color); + color: var(--dark-color); +} +.moviesfeed__rating { + background: var(--bright-color); + padding: 0.5rem; + display: inline-block; + text-transform: uppercase +} + +/* show-hide */ +.moviesfeed__full .moviesfeed__details { + display: none; + } +.moviesfeed__full.details--open .moviesfeed__details { + display: block; +} +.moviesfeed__full.details--open .moviesfeed__content, +.moviesfeed__full.details--open .movie__header { + position: static; +} +.moviesfeed__full.details--open .moviesfeed__btn { + left: auto; + right: 0px; + bottom: auto; + top: 0px; +} +.moviesfeed__full.details--open .moviesfeed__content, +.moviesfeed__full.details--open .movie__title { + background-color: var(--light-color); + color: var(--main-txt-color); + height: auto; + } +.moviesfeed__full.details--open .movie__title { + font-size: 1.75rem; +} + +/* paging */ +.paging { + text-align: center; + margin: var(--main-padding) 0 calc( 3 * var(--main-padding) ); +} +.paging__previous, .paging__next { + cursor: pointer +} +.paging__previous, .paging__next, .paging__count { + display: inline-block; + padding: var(--main-padding); + background: var(--light-color); + color: var(--dark-color); + font-weight: bold; +} +.paging__previous:hover, .paging__next:hover { + background: var(--bright-color); +} + +/* footer */ +.footer { + padding:calc( 2 * var(--main-padding) ) 0; + border-top: 5px dashed var(--bright-color); + color: var(--bright-color); + text-align: center; + } + + + /* MEDIA QUERIES + ============== */ + +@media (min-width: 768px) { + body { + display: flex; + flex-direction: column; + min-height: 100vh; + } + #root { + flex: 1; + display: flex; + flex-direction: row; + align-items: center; + } + #root, .maincontent, .search__form { + width: 100%; + } + + .search__input { + width: auto; + padding: 0.35em 0.75em; + flex: 2; + } + .search__btn { + width: auto; + flex: 1; + } + .search__input-wrapper { + display: inline-block; + } + + /* MAIN */ + .moviesfeed { + display: flex; + flex-flow: row wrap; + } + .moviesfeed article { + width: 25%; + order: 1; + } + .moviesfeed article.active { + width: 100%; + order: 0; + } + .moviesfeed__full{ + padding-top: 130%; + } + + .moviesfeed__full.details--open { + background-size: auto 100%; + background-color: var(--light-color); + padding-top: 0; + padding-left: 25%; + background-position: center left; + } + .moviesfeed__details-list { + padding-right: 20%; + } + .moviesfeed__full.details--open .movie__title em { + display: block; + } + + /* GRID PADDINGS */ + .moviesfeed__full { + margin-right: var(--main-padding); + margin-left: var(--main-padding); + } +} + +@media (min-width: 960px) { + .container {max-width: 930px} +} + +@media (min-width: 1200px) { + .container {max-width: 1170px} + .moviesfeed article { + width: 20%; + } +} + +@media (min-width: 1440px) { + .container { + max-width: 1410px + } +} \ No newline at end of file