diff --git a/README.md b/README.md index 4c8fd7876..e6aca5a48 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ -# Project Movies +# Project Movies 🍿🎥 -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +We did a movie page using react. ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +We had some problem with the intro and to upload it on netlify! ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +https://annandreas-popular-movies.netlify.app/ diff --git a/code/package-lock.json b/code/package-lock.json index bb51e893e..3afb328bc 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -16,7 +16,8 @@ "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^6.10.0" }, "devDependencies": { "react-scripts": "5.0.1" @@ -3124,6 +3125,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", + "engines": { + "node": ">=14" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -14384,6 +14393,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", + "dependencies": { + "@remix-run/router": "1.5.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", + "dependencies": { + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -19509,6 +19548,11 @@ "source-map": "^0.7.3" } }, + "@remix-run/router": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==" + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -27684,6 +27728,23 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "dev": true }, + "react-router": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", + "requires": { + "@remix-run/router": "1.5.0" + } + }, + "react-router-dom": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", + "requires": { + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" + } + }, "react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", diff --git a/code/package.json b/code/package.json index 7aad26ebc..152f79a1a 100644 --- a/code/package.json +++ b/code/package.json @@ -11,7 +11,8 @@ "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^6.10.0" }, "scripts": { "start": "react-scripts start", diff --git a/code/public/_redirects b/code/public/_redirects new file mode 100644 index 000000000..50a463356 --- /dev/null +++ b/code/public/_redirects @@ -0,0 +1 @@ +/* /index.html 200 \ No newline at end of file diff --git a/code/public/favicon.ico b/code/public/favicon.ico new file mode 100644 index 000000000..7a5ef16be Binary files /dev/null and b/code/public/favicon.ico differ diff --git a/code/public/favicoon.ico b/code/public/favicoon.ico new file mode 100644 index 000000000..0fb31f21b --- /dev/null +++ b/code/public/favicoon.ico @@ -0,0 +1 @@ + diff --git a/code/public/index.html b/code/public/index.html index e6730aa66..631c9b834 100644 --- a/code/public/index.html +++ b/code/public/index.html @@ -1,6 +1,5 @@ - @@ -13,7 +12,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - Technigo React App + Popular Movies @@ -30,5 +29,4 @@ To create a production bundle, use `npm run build` or `yarn build`. --> - diff --git a/code/src/App.js b/code/src/App.js index f2007d229..c82d3ab44 100644 --- a/code/src/App.js +++ b/code/src/App.js @@ -1,9 +1,24 @@ -import React from 'react'; +import React from 'react' +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' +import MovieList from 'components/MovieList' +import MovieDetails from 'components/MovieDetails' +import NotFound from 'components/NotFound' export const App = () => { return ( -
- Find me in src/app.js! -
+ + + } /> + } /> + } /> + } /> + + + ); } + +export default App; +/* BrowserRouter= Wrapper for everything / main wrapper for the whole wrap */ +/* Route= Wrapper for every component */ +/* Route path= Path to a single component */ diff --git a/code/src/components/Header.js b/code/src/components/Header.js new file mode 100644 index 000000000..db0f9c747 --- /dev/null +++ b/code/src/components/Header.js @@ -0,0 +1,29 @@ +/* eslint-disable jsx-a11y/label-has-associated-control */ +/* import React from 'react'; + +const Header = () => { +/* const [category, setCategory] = useState('popular'); */ + +/* return ( +
+
+ +
+ Latest + Series + Upcoming +
+
+
+ ) +} + +export default Header; + */ +/* */ \ No newline at end of file diff --git a/code/src/components/Intro.js b/code/src/components/Intro.js new file mode 100644 index 000000000..9fcd919c8 --- /dev/null +++ b/code/src/components/Intro.js @@ -0,0 +1,13 @@ +import React from 'react' + +const Popcorn = () => ( +
+ + + popcorngif +
Get your snacks ready
+
+
+) + +export default Popcorn diff --git a/code/src/components/MovieDetails.js b/code/src/components/MovieDetails.js new file mode 100644 index 000000000..781bd971a --- /dev/null +++ b/code/src/components/MovieDetails.js @@ -0,0 +1,67 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +import React, { useState, useEffect } from 'react' +import { useParams, useNavigate } from 'react-router-dom' +import NotFound from 'components/NotFound' + +/* PAGE 2 */ +const MovieDetails = () => { + const [details, setDetails] = useState([]); + const navigate = useNavigate(); + const { id } = useParams() + const onBackButtonClick = () => { + navigate(-1); + } + + const FetchDetails = () => { + fetch(`https://api.themoviedb.org/3/movie/${id}?api_key=e865fc7d6c1eaa875454193ac1851471&language=en-US`) + .then((response) => response.json()) + .then((data) => setDetails(data)) + .catch((error) => { + console.log(error) + if (error) { + return ( + ) + } + }) + } + // eslint-disable-next-line no-unused-vars + const handleBackButton = (event) => { + if (event.KeyCode === 13) { + onBackButtonClick(); + } + }; + useEffect(() => { + FetchDetails() + }) + + return ( +
+
+
+
+ + + +
+
+
+ {details.title} +
+
+

{details.title} ⭐️{Math.round(details.vote_average * 10) / 10}

+

{details.overview}

+
+
+
+ ); +} + +export default MovieDetails; + +/* To round rating number to one decimal */ +/* const roundedNumber = Math.round(movieDetails.vote_average * 10) / 10 */ diff --git a/code/src/components/MovieList.js b/code/src/components/MovieList.js new file mode 100644 index 000000000..0f77f413e --- /dev/null +++ b/code/src/components/MovieList.js @@ -0,0 +1,51 @@ +/* eslint-disable no-shadow */ +import React, { useState, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import Popcorn from './Intro'; +/* import Header from './Header'; */ +/* STARTPAGE */ +const MovieList = () => { + const [list, setList] = useState([]); + const [loading, setLoading] = useState(false); + + /* Fetch function that allows us to get the movie titles, images from API */ + const FetchMovies = () => { + fetch('https://api.themoviedb.org/3/movie/popular?api_key=e865fc7d6c1eaa875454193ac1851471&language=en-US&page=1') + .then((response) => response.json()) + .then((data) => { + setList(data.results) + }) + } + /* A call back function - this useEffect hook awakens the FetchMovies function above */ + useEffect(() => { + FetchMovies() + setLoading(true); + setTimeout(() => setLoading(false), 2000) + }, []) + + /* This return shows the img, titles, rdate & the id on our HTML page */ + return ( +
+ {loading ? () : ( + <> + {/*
*/} +
+ {list.map((movie) => ( +
+ + {movie.title} +
+

{movie.title}

+

Released {movie.release_date}

+
+ +
+ ))} +
+ + )} +
+ ) +} + +export default MovieList; \ No newline at end of file diff --git a/code/src/components/NotFound.js b/code/src/components/NotFound.js new file mode 100644 index 000000000..f0322d10a --- /dev/null +++ b/code/src/components/NotFound.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; + +const NotFound = () => { + const navigate = useNavigate(); + const onHomeButtonClick = () => { + navigate('/'); + } + return ( +
+

Page not found

+ +
); +} +export default NotFound; \ No newline at end of file diff --git a/code/src/index.css b/code/src/index.css index 4a1df4db7..128389243 100644 --- a/code/src/index.css +++ b/code/src/index.css @@ -5,9 +5,342 @@ body { sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + background: black; + color: white; + overflow-x: hidden; + cursor: url("data:image/svg+xml;utf8,🍿") + 16 0, +auto; } - code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } +*{ + box-sizing: border-box; +} + +.header-container { + padding: 10px; + background-color: #4c0000; + cursor: url("data:image/svg+xml;utf8,🍿") + 16 0, +auto; +} + + +/* PAGE 1 */ +.movie-container { + display: grid; + grid-template-columns: 1fr 1fr; +} +.movie-container a { + position: relative; + text-decoration: none; +} +.movie-wrapper img { + width: 100%; +} +.movie-wrapper:hover .details{ + visibility: visible; +} + +/* H1 & P film info*/ +.details { + color: #fff; + visibility: hidden; + font-size: 20px; + left: 0; + bottom: 0; + margin: 10px; + position: absolute; + right: 0; + text-decoration: none; +} +.details:hover h1, +.details:hover p { +color: #fff; +} +.movie-wrapper { +position: relative; +} +.movie-wrapper:hover img{ + -webkit-filter: brightness(50%); + filter: brightness(50%); + cursor: url("data:image/svg+xml;utf8,🍿") + 16 0, +auto; +} + + +/* DETAILS-PAGE */ +.background { + min-height: 100vh; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + display: flex; + flex-direction: column; +} + +.movie-details { + flex-direction: column; + justify-content: center; + align-items: center; + margin-left: 15px; + padding-top: 15px; +} +.movie-details img { + border: solid white 1px; +} + +.details-page-2 { + background-color: rgba(0, 0, 0, 0.585); + max-width: 410px; + margin: 17px; + max-height: 210px; + top: 520px; + transition: .2s ease-in-out; +} + .details-page-2:hover { + transition: 0.35s ease-in-out; + transform: scale(1.4); + } +.details-page-2 h3 { + font-size: 23px; + margin-bottom: -5px; + padding: 2px; +} +.details-page-2 p { + margin-bottom: 20px; +} + + +/* LOADING */ +.loading-movies { + justify-content: center; + align-items: center; + height:auto; + height: 100vh; + overflow:auto; +} +.loading-movies { + text-align: center; + margin: 15px; +} +.loading-intro { + animation-name: loadintro; + margin-bottom: 20px; + text-align: center; + justify-self: center; + display: flex; + font-size: 50px; + flex-direction: column; + padding: 40px; + padding-top: 100px; +} + +/* INTRO PICTURE POPCORN MAN*/ +.loading-intro img { + width: 300px; +} +.center { + display: block; + margin-left: auto; + margin-right: auto; +} + + +/* THE BACK BUTTON */ +.button { + position: absolute; + left: 21%; + top: 7%; + transform: translate(-50%, -50%); + transform: rotate(90deg); + cursor: pointer; +} +.button span { + display: block; + width: 4.5vw; + height: 4.5vw; + border-bottom: 5px solid white; + border-right: 5px solid white; + transform: rotate(45deg); + margin: -10px; + animation: animate 2s infinite; + cursor: pointer; + +} +.button span:nth-child(2) { + animation-delay: -0.2s; + cursor: pointer; + +} +.button span:nth-child(3) { + animation-delay: -0.4s; + cursor: pointer; + +} +@keyframes animate { + 0% { + opacity: 0; + transform: rotate(45deg) translate(-20px, -20px); + } + 50% { + opacity: 1; + } + 100% { + opacity: 0; + transform: rotate(45deg) translate(20px, 20px); + } +} + + + + +/* DROPDOWN MENU */ +/* the menu button */ +button { + background: none; + padding: 16px; + font-size: 20px; + border: none; + color: white; + cursor: url("data:image/svg+xml;utf8,🍿") + 16 0, +auto; +} +.dropbtn { + background-color: orange; + color: white; + padding: 16px; + font-size: 16px; + border: none; +} +.dropdown { + position: relative; + display: inline-block; +} +.dropdown-content { + display: none; + position: absolute; + background-color: #0b0b0b; + min-width: 160px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; +} +/* inside font color */ +.dropdown-content a { + color: rgb(243, 243, 243); + padding: 12px 16px; + text-decoration: none; + display: block; +} + +/* dropdown list hover color pink */ +.dropdown-content a:hover {background-color: rgb(159, 159, 159);} +.dropdown:hover .dropdown-content {display: block;} +/* hover color over button */ +/*.dropdown:hover .dropbtn {background-color: blue;} */ + + + + + + +/* DESKTOP */ +@media (min-width: 1024px) { + .movie-container{ + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + } + .button { + position: absolute; + left: 7%; + top: 7%; + } + .button span { + display: block; + width: 1.5vw; + height: 1.5vw; + border-bottom: 5px solid white; + border-right: 5px solid white; + transform: rotate(45deg); + margin: -10px; + animation: animate 2s infinite; +} +.background { + min-height: 100vh; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + display: flex; + flex-direction: row; +} +.details-page-2 { + background-color: rgba(0, 0, 0, 0.585); + max-width: 410px; + margin: 17px; + max-height: 210px; + position: absolute; + left: 360px; + top: 300px; + } + .loading-intro img { + width: 500px; +} +.center { + display: block; + margin-left: auto; + margin-right: auto; +} +} + + /* TABLET */ + @media (min-width: 667px) and (max-width: 1024px){ + .movie-container{ + grid-template-columns: 1fr 1fr 1fr; + } + .button { + position: absolute; + left: 10%; + top: 2%; + } + .button span { + display: block; + width: 3.5vw; + height: 3.5vw; + border-bottom: 5px solid rgb(255, 255, 255); + border-right: 5px solid rgb(255, 255, 255); + transform: rotate(45deg); + margin: -10px; + animation: animate 2s infinite; + } + .background { + min-height: 100vh; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + display: flex; + flex-direction: row; + } + .details-page-2 { + background-color: rgba(0, 0, 0, 0.585); + max-width: 410px; + margin: 17px; + max-height: 210px; + top: 520px; + position: absolute; + right: 18px; + top: 308px; + } + .loading-intro img { + width: 500px; + } + .center { + display: block; + margin-left: auto; + margin-right: auto; + } + } \ No newline at end of file