diff --git a/.env b/.env
new file mode 100644
index 00000000..fb7d8c4a
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+VITE_DBAPI_KEY = 5f524441926a384bdad27fc1fd156e93
\ No newline at end of file
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 4dcb4390..4451523c 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -2,19 +2,20 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
- 'eslint:recommended',
- 'plugin:react/recommended',
- 'plugin:react/jsx-runtime',
- 'plugin:react-hooks/recommended',
+ "eslint:recommended",
+ "plugin:react/recommended",
+ "plugin:react/jsx-runtime",
+ "plugin:react-hooks/recommended",
],
- ignorePatterns: ['dist', '.eslintrc.cjs'],
- parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
- settings: { react: { version: '18.2' } },
- plugins: ['react-refresh'],
+ ignorePatterns: ["dist", ".eslintrc.cjs"],
+ parserOptions: { ecmaVersion: "latest", sourceType: "module" },
+ settings: { react: { version: "18.2" } },
+ plugins: ["react-refresh"],
rules: {
- 'react-refresh/only-export-components': [
- 'warn',
+ "react/prop-types": "off",
+ "react-refresh/only-export-components": [
+ "warn",
{ allowConstantExport: true },
],
},
-}
+};
diff --git a/README.md b/README.md
index 83e5e37a..f2d1aae2 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,7 @@
# Movie Site Project
-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.
+Movie single page application (SPA) project,by using the API from https://www.themoviedb.org/. Learned how to use BrowserRouter, Routes, Route and useParams().
## Getting Started with the Project
@@ -24,11 +22,18 @@ npm i && code . && npm run dev
### 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 started to layout what components we need and want to create. We also looked into the API what data we'd like to use. At first we code together and tried doing pair-programming for the BrowserRouter, Routes, etc. After a while we split up the work and code in different branches.
+
+We mostly gathered our information from the bootcamp material or the lovely internet. If we had more creativity and time, we would have done de styling different and might have fetched other data from TMDB.
+
+#### Additional
+
+- Add disclamer: "This [website, program, service, application, product] uses TMDB and the TMDB APIs but is not endorsed, certified, or otherwise approved by TMDB."
### 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.
+[![Netlify Status](https://api.netlify.com/api/v1/badges/832d0052-da1e-49ae-9040-74ff2906a5c8/deploy-status)](https://app.netlify.com/sites/nathalies-sofias-project-movies/deploys)
+https://nathalies-sofias-project-movies.netlify.app/
## Instructions
diff --git a/index.html b/index.html
index 1615ccc7..a237c819 100644
--- a/index.html
+++ b/index.html
@@ -1,13 +1,13 @@
-
-
-
-
- Movie Site Project
-
-
-
-
-
+
+
+
+
+ Nathalie's & Sofia's Movie Site Project
+
+
+
+
+
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 00000000..82916ac5
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,5 @@
+
+[[redirects]]
+ from = "/*"
+ to = "/index.html"
+ status = 200
\ No newline at end of file
diff --git a/package.json b/package.json
index a3bd4ec3..0024140b 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
},
"dependencies": {
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.22.3"
},
"devDependencies": {
"@types/react": "^18.2.15",
diff --git a/public/pexels-tima-miroshnichenko-7991428-large.jpg b/public/pexels-tima-miroshnichenko-7991428-large.jpg
new file mode 100644
index 00000000..4b6ed993
Binary files /dev/null and b/public/pexels-tima-miroshnichenko-7991428-large.jpg differ
diff --git a/public/popcorn.png b/public/popcorn.png
new file mode 100644
index 00000000..b96aa2ad
Binary files /dev/null and b/public/popcorn.png differ
diff --git a/public/vite.svg b/public/vite.svg
deleted file mode 100644
index e7b8dfb1..00000000
--- a/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index 1091d431..af5afe39 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,3 +1,31 @@
+import { BrowserRouter, Routes, Route } from "react-router-dom"
+import { Footer } from "./components/footer/Footer"
+import { Header } from "./components/header/Header"
+import { Details } from "./components/details/Details"
+import { Listing } from "./components/listing/Listing"
+import { NotFound } from "./components/404/NotFound"
+import { Genres } from "./components/genres/Genres"
+
export const App = () => {
- return Find me in src/app.jsx!
;
-};
+ return (
+ <>
+
+
+
+
+ {/* Conditional that makes the "page content" switch between components, depending on the URL*/}
+ } errorElement={ } />
+ }
+ errorElement={ }
+ />
+ } />
+ } />
+
+
+
+
+ >
+ )
+}
diff --git a/src/assets/RubikScribble-Regular.ttf b/src/assets/RubikScribble-Regular.ttf
new file mode 100644
index 00000000..fbc42674
Binary files /dev/null and b/src/assets/RubikScribble-Regular.ttf differ
diff --git a/src/assets/left-arrows-white.png b/src/assets/left-arrows-white.png
new file mode 100644
index 00000000..d368c9d2
Binary files /dev/null and b/src/assets/left-arrows-white.png differ
diff --git a/src/components/404/NotFound.css b/src/components/404/NotFound.css
new file mode 100644
index 00000000..eafb9eda
--- /dev/null
+++ b/src/components/404/NotFound.css
@@ -0,0 +1,35 @@
+.not-found-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 12rem 3rem 20rem;
+ text-align: center;
+}
+
+.not-found-container h1 {
+ margin-top: 4rem;
+ font-size: 4rem;
+}
+
+.not-found-container p {
+ margin-top: 16px;
+ font-size: 2rem;
+}
+
+.not-found-container p::after {
+ content: " 👀";
+}
+
+.link-back {
+ margin: 24px;
+}
+
+.link-back::after {
+ content: " ›";
+}
+
+.link-back:hover {
+ text-decoration: underline;
+ color: var(--decor-color);
+ cursor: pointer;
+}
diff --git a/src/components/404/NotFound.jsx b/src/components/404/NotFound.jsx
new file mode 100644
index 00000000..8ae17e15
--- /dev/null
+++ b/src/components/404/NotFound.jsx
@@ -0,0 +1,21 @@
+import { Link } from "react-router-dom"
+import notFoundImg from "/pexels-tima-miroshnichenko-7991428-large.jpg"
+import "./NotFound.css"
+
+export const NotFound = () => {
+ return (
+
+
Oups!
+
Nothing to see here
+
+ Back to the movies
+
+
+ )
+}
diff --git a/src/components/details/Details.css b/src/components/details/Details.css
new file mode 100644
index 00000000..94c2e5f7
--- /dev/null
+++ b/src/components/details/Details.css
@@ -0,0 +1,139 @@
+.details-container {
+ height: 100svh;
+ padding: 5%;
+ color: white;
+ display: flex;
+ flex-wrap: wrap;
+ /* align-items: flex-end;
+ align-content: flex-end; */
+ justify-items: center;
+}
+
+.back-btn-wrapper {
+ align-self: flex-start;
+ position: absolute;
+ top: 7%;
+ display: none;
+}
+
+.back-button {
+ width: 35px;
+ height: 35px;
+ filter: drop-shadow(0 0 0.4rem black);
+}
+
+.poster {
+ object-fit: cover;
+ height: 100%;
+ max-width: 200px;
+ width: auto;
+ border: 6px solid white;
+ box-shadow: var(--box-shadow);
+ margin-left: 16px;
+ position: relative;
+}
+
+.details {
+ width: 100%;
+ background: radial-gradient(rgba(0, 0, 0, 0) 100%, rgb(0, 0, 0) 70%);
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ align-self: flex-start;
+ justify-items: center;
+ gap: 0.5rem;
+ margin-bottom: 30px;
+}
+
+.summary {
+ padding: 1rem 1rem 0 1rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.title {
+ text-shadow: var(--text-shadow);
+ font-size: 28px;
+ word-wrap: break-word;
+}
+
+.desc {
+ font-size: 16px;
+}
+
+.rank-time-container {
+ display: flex;
+ gap: 2rem;
+}
+
+.ranking,
+.runtime {
+ background-color: rgba(0, 0, 0, 0.4);
+ padding: 0.2rem;
+ width: fit-content;
+ color: rgba(255, 255, 255, 0.869);
+ font-weight: 600;
+ font-size: 0.875rem;
+ border-radius: 3px;
+ font-style: italic;
+}
+
+.ranking::before {
+ content: "⭐️ ";
+ display: inline;
+}
+
+.ranking::after {
+ content: " / 10";
+ display: inline;
+}
+
+@media all and (min-width: 668px) {
+ .details-container {
+ flex-direction: row;
+ align-content: flex-end;
+ }
+
+ .details {
+ align-items: flex-end;
+ align-content: flex-end;
+ }
+
+ .back-btn-wrapper {
+ left: 20px;
+ display: block;
+ }
+
+ .summary {
+ width: 55%;
+ }
+
+ .poster {
+ max-width: 245px;
+ }
+ .title {
+ font-size: 38px;
+ }
+
+ .desc {
+ font-size: 18px;
+ }
+}
+
+@media all and (min-width: 1028px) {
+ .poster {
+ max-width: 295px;
+ }
+ .summary {
+ width: 65%;
+ }
+
+ .title {
+ font-size: 3rem;
+ }
+
+ .desc {
+ font-size: 20px;
+ }
+}
diff --git a/src/components/details/Details.jsx b/src/components/details/Details.jsx
new file mode 100644
index 00000000..6561c47d
--- /dev/null
+++ b/src/components/details/Details.jsx
@@ -0,0 +1,78 @@
+import { Link, useParams } from "react-router-dom"
+import "./Details.css"
+import { useEffect, useState } from "react"
+import backButton from "../../assets/left-arrows-white.png"
+import { GenreList } from "../genreList/GenreList"
+
+export const Details = () => {
+ const movie = useParams()
+ const [results, setResults] = useState()
+ const API_KEY = import.meta.env.VITE_DBAPI_KEY
+ const API_LANG = "en-US"
+ const POSTER_URL = "https://image.tmdb.org/t/p"
+
+ useEffect(() => {
+ const fetchDetails = async () => {
+ try {
+ const response = await fetch(
+ `https://api.themoviedb.org/3/movie/${movie.slug}?api_key=${API_KEY}&language=${API_LANG}`
+ )
+ if (!response.ok) {
+ throw Error("Something wrong with the fetch")
+ }
+ const data = await response.json()
+ setResults(data)
+ } catch (error) {
+ console.error("Error", error)
+ setResults([])
+ }
+ }
+
+ fetchDetails()
+ }, [])
+
+ return (
+ <>
+ {results && (
+
+
+
+
+
+
+
+
+
+
{results.title}
+
+
+ {Math.round(results.vote_average * 100) / 100}
+
+
{results.runtime} minutes
+
+
{results.overview}
+
+
+
+
+
+
+ )}
+ >
+ )
+}
diff --git a/src/components/error/Error.css b/src/components/error/Error.css
new file mode 100644
index 00000000..9bcce486
--- /dev/null
+++ b/src/components/error/Error.css
@@ -0,0 +1,3 @@
+.error-msg {
+ padding: 2rem;
+}
diff --git a/src/components/error/Error.jsx b/src/components/error/Error.jsx
new file mode 100644
index 00000000..fedfeb18
--- /dev/null
+++ b/src/components/error/Error.jsx
@@ -0,0 +1,5 @@
+import "./Error.css"
+
+export const Error = ({ m }) => {
+ return {m}
+}
diff --git a/src/components/footer/Footer.css b/src/components/footer/Footer.css
new file mode 100644
index 00000000..ec2b636b
--- /dev/null
+++ b/src/components/footer/Footer.css
@@ -0,0 +1,55 @@
+footer {
+ position: relative;
+ padding: 1rem;
+ width: 100%;
+ bottom: 0;
+ color: var(--font-color);
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+}
+
+.contact > *,
+.contact li {
+ padding: 0 1rem;
+}
+
+.contact span {
+ font-weight: 600;
+ font-size: 1.2rem;
+}
+
+.contact a {
+ display: block;
+ padding: 2px;
+}
+
+.contact span::after {
+ content: "•";
+ display: inline;
+ padding: 0 0.5rem;
+}
+
+.contact a::after {
+ content: " ›";
+ display: inline;
+}
+
+.disclaimer {
+ font-size: x-small;
+ width: 100%;
+ text-align: center;
+}
+
+@media all and (min-width: 668px) {
+ .contact a {
+ display: inline;
+ }
+
+ .contact > *,
+ .contact li {
+ display: inline-block;
+ }
+}
diff --git a/src/components/footer/Footer.jsx b/src/components/footer/Footer.jsx
new file mode 100644
index 00000000..85bf05c9
--- /dev/null
+++ b/src/components/footer/Footer.jsx
@@ -0,0 +1,29 @@
+import "./Footer.css"
+
+export const Footer = () => {
+ return (
+
+
+
+ Disclaimer: This website uses TMDB and the TMDB APIs but is not
+ endorsed, certified, or otherwise approved by TMDB.
+
+
+ )
+}
diff --git a/src/components/genreList/GenreList.css b/src/components/genreList/GenreList.css
new file mode 100644
index 00000000..6d80245b
--- /dev/null
+++ b/src/components/genreList/GenreList.css
@@ -0,0 +1,22 @@
+
+.genre-list {
+ display: flex;
+ flex: 0 0 auto;
+ white-space: nowrap;
+ flex-wrap: wrap;
+}
+
+.genre {
+ display: inline;
+}
+
+.genre:not(:last-of-type):after {
+ content: " • ";
+ display: inline;
+ padding: 1rem;
+}
+
+.genre > a::after {
+ content: " ›";
+ display: inline;
+}
diff --git a/src/components/genreList/GenreList.jsx b/src/components/genreList/GenreList.jsx
new file mode 100644
index 00000000..a0b933aa
--- /dev/null
+++ b/src/components/genreList/GenreList.jsx
@@ -0,0 +1,22 @@
+import "./GenreList.css"
+import { Link, NavLink } from "react-router-dom"
+
+export const GenreList = ({ genreArray, n }) => {
+ return (
+
+ {genreArray.map(genre => {
+ return (
+
+ {n ? (
+ {genre.name}
+ ) : (
+ {genre.name}
+ )}
+
+ )
+ })}
+
+ )
+}
diff --git a/src/components/genres/Genres.css b/src/components/genres/Genres.css
new file mode 100644
index 00000000..20d702cf
--- /dev/null
+++ b/src/components/genres/Genres.css
@@ -0,0 +1,19 @@
+article {
+ padding: 5%;
+ color: white;
+ display: flex;
+ flex-direction: column;
+ /* align-items: flex-end;
+ align-content: flex-end; */
+ justify-items: center;
+}
+
+.title {
+ text-shadow: var(--text-shadow);
+ font-size: 28px;
+ word-wrap: break-word;
+}
+
+.desc {
+ font-size: 16px;
+}
\ No newline at end of file
diff --git a/src/components/genres/Genres.jsx b/src/components/genres/Genres.jsx
new file mode 100644
index 00000000..d707d2eb
--- /dev/null
+++ b/src/components/genres/Genres.jsx
@@ -0,0 +1,24 @@
+import { useParams } from "react-router-dom"
+import "./Genres.css"
+import { Listing } from "../listing/Listing"
+import genreJson from "../../data/genre-descriptions.json"
+
+export const Genres = () => {
+ const { genreId } = useParams()
+ const genre = genreJson.genres.find(
+ genre => genre.id == genreId || genre.id == 0
+ )
+
+ return (
+ <>
+
+ {genre.name}
+ {genre.description}
+
+
+ >
+ )
+}
diff --git a/src/components/header/Header.css b/src/components/header/Header.css
new file mode 100644
index 00000000..4cf87b59
--- /dev/null
+++ b/src/components/header/Header.css
@@ -0,0 +1,45 @@
+header {
+ position: relative;
+ padding: 12px;
+ width: 100%;
+ top: 0;
+ color: var(--font-color);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+}
+
+nav {
+ width: 100%;
+ display: flex;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.heading {
+ font-size: 18px;
+ width: 100%;
+}
+
+.heading > span {
+ font-weight: 900;
+ font-size: 20px;
+ display: block;
+ font-family: "Rubik Scribble";
+}
+
+@media all and (min-width: 668px) {
+ .heading {
+ font-size: 1.2rem;
+ }
+ .heading > span {
+ font-size: 2rem;
+ }
+}
+
+@media all and (min-width: 1028px) {
+ .heading > span {
+ font-size: 4rem;
+ }
+}
diff --git a/src/components/header/Header.jsx b/src/components/header/Header.jsx
new file mode 100644
index 00000000..c5c14bb8
--- /dev/null
+++ b/src/components/header/Header.jsx
@@ -0,0 +1,16 @@
+import "./Header.css"
+import { NavLink } from "react-router-dom"
+
+export const Header = () => {
+ return (
+
+ )
+}
diff --git a/src/components/listing/Listing.css b/src/components/listing/Listing.css
new file mode 100644
index 00000000..3c6a1da6
--- /dev/null
+++ b/src/components/listing/Listing.css
@@ -0,0 +1,72 @@
+.movie-card {
+ display: flex;
+ flex-direction: column;
+ gap: 0.2rem;
+}
+
+.load-more-wrapper {
+ display: grid;
+}
+
+#load-more-btn {
+ align-items: center;
+ background-color: #fff;
+ border: 2px solid #000;
+ box-sizing: border-box;
+ color: #000;
+ cursor: pointer;
+ display: inline-flex;
+ fill: #000;
+ font-family: Inter, sans-serif;
+ font-size: 16px;
+ font-weight: 600;
+ height: 48px;
+ justify-content: center;
+ letter-spacing: -0.8px;
+ line-height: 24px;
+ min-width: 140px;
+ outline: 0;
+ padding: 0 17px;
+ text-align: center;
+ text-decoration: none;
+ transition: all 0.3s;
+ user-select: none;
+ -webkit-user-select: none;
+ touch-action: manipulation;
+}
+
+#load-more-btn:focus {
+ color: #171e29;
+}
+
+#load-more-btn:hover {
+ border-color: var(--decor-color);
+ color: var(--decor-color);
+ fill: var(--decor-color);
+}
+
+#load-more-btn:active {
+ border-color: var(--decor-color);
+ color: var(--decor-color);
+ fill: var(--decor-color);
+}
+
+@media (min-width: 768px) {
+ .button-59 {
+ min-width: 170px;
+ }
+}
+
+@media all and (min-width: 668px) {
+ .movie-card {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ }
+}
+
+@media all and (min-width: 1028px) {
+ .movie-card {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ }
+}
diff --git a/src/components/listing/Listing.jsx b/src/components/listing/Listing.jsx
new file mode 100644
index 00000000..95412066
--- /dev/null
+++ b/src/components/listing/Listing.jsx
@@ -0,0 +1,74 @@
+import { useEffect, useState } from "react"
+import "./Listing.css"
+import { MovieCard } from "../movieCards/MovieCard"
+import { Error } from "../error/Error"
+
+export const Listing = ({ genreId, genre }) => {
+ const [results, setResults] = useState([])
+ const [page, setPage] = useState(1)
+ const API_KEY = import.meta.env.VITE_DBAPI_KEY
+ const API_LANG = "en-US"
+
+ const fetchMovie = async () => {
+ try {
+ const response = await fetch(
+ `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}&language=${API_LANG}&page=${page}`
+ )
+ if (!response.ok) {
+ throw Error("Something wrong with the fetch")
+ }
+ const data = await response.json()
+ let movies = data.results
+
+ // Is there a genre? Filter for match
+ if (genre) {
+ movies = movies.filter((movie) =>
+ movie.genre_ids.includes(Number(genreId))
+ )
+ }
+
+ // If page is over 1, add new results to previous results
+ if (page > 1) {
+ const newData = movies.map((movie) => ({
+ ...movie,
+ uniqueKey: `${movie.id}-${page}`, // Ensure unique key
+ }))
+ setResults((prevResults) => [...prevResults, ...newData])
+ } else {
+ // Otherwise, just take the results
+ setResults(movies)
+ }
+ } catch (error) {
+ console.error("Error", error)
+ }
+ }
+
+ useEffect(() => {
+ fetchMovie()
+ }, [])
+
+ const loadMore = () => {
+ setPage((prevPage) => prevPage + 1)
+ fetchMovie()
+ }
+
+ return (
+ <>
+
+ {results.length > 0 ? (
+ results.map((movie, index) => {
+ return
+ })
+ ) : (
+
+ )}
+
+
+
+ {" "}
+ Load more{" "}
+
+
+ >
+ )
+}
diff --git a/src/components/movieCards/MovieCard.css b/src/components/movieCards/MovieCard.css
new file mode 100644
index 00000000..88b9bbd1
--- /dev/null
+++ b/src/components/movieCards/MovieCard.css
@@ -0,0 +1,56 @@
+h2 {
+ color: white;
+ font-size: 26px;
+}
+
+.movie-title > p {
+ color: white;
+}
+
+.movie-poster-container,
+.movie-image {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ max-width: 667px;
+ height: auto;
+ position: relative;
+}
+
+.movie-poster-container:hover .movie-image {
+ filter: brightness(30%);
+ transition: all 0.2s ease-in-out;
+}
+
+.movie-title {
+ position: absolute;
+ top: 0;
+ left: 10px;
+ right: 0;
+ bottom: 20px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ align-items: flex-start;
+ gap: 0.5rem;
+ display: none;
+ transform: scaleX(1);
+}
+
+.movie-poster-container:hover .movie-title {
+ display: flex;
+ cursor: pointer;
+ transition: all 0.2s ease-in-out;
+}
+
+@media all and (min-width: 668px) {
+ .movie-poster-container {
+ max-width: 1027px;
+ }
+}
+
+@media all and (min-width: 1028px) {
+ .movie-poster-container {
+ max-width: 100%;
+ }
+}
diff --git a/src/components/movieCards/MovieCard.jsx b/src/components/movieCards/MovieCard.jsx
new file mode 100644
index 00000000..01189e87
--- /dev/null
+++ b/src/components/movieCards/MovieCard.jsx
@@ -0,0 +1,21 @@
+import "./MovieCard.css"
+import { Link } from "react-router-dom"
+
+export const MovieCard = ({ data }) => {
+ const POSTER_URL = "https://image.tmdb.org/t/p/w500"
+ return (
+
+
+
+
+
{data.title}
+
Released {data.release_date}
+
+
+
+ )
+}
diff --git a/src/data/genre-descriptions.json b/src/data/genre-descriptions.json
new file mode 100644
index 00000000..f7920c83
--- /dev/null
+++ b/src/data/genre-descriptions.json
@@ -0,0 +1,104 @@
+{
+ "genres": [
+ {
+ "id": 28,
+ "name": "Action",
+ "description": "Exciting and fast-paced films focusing on physical feats, stunts, and thrilling sequences."
+ },
+ {
+ "id": 12,
+ "name": "Adventure",
+ "description": "Movies centered around exciting journeys, discoveries, and adventures in foreign worlds."
+ },
+ {
+ "id": 16,
+ "name": "Animation",
+ "description": "Films created with animated images and characters, often targeting a younger audience but also appealing to adults."
+ },
+ {
+ "id": 35,
+ "name": "Comedy",
+ "description": "Movies intended to make the audience laugh, often through humorous situations, dialogues, and characters."
+ },
+ {
+ "id": 80,
+ "name": "Crime",
+ "description": "Engaging films focusing on crimes, investigations, and solving mysteries."
+ },
+ {
+ "id": 99,
+ "name": "Documentary",
+ "description": "Movies documenting real events, people, or subjects, often aiming to inform, educate, or entertain."
+ },
+ {
+ "id": 18,
+ "name": "Drama",
+ "description": "Films focusing on serious themes, emotional storylines, and complex characters."
+ },
+ {
+ "id": 10751,
+ "name": "Family",
+ "description": "Movies suitable for a broad audience, including families with children, often with a positive message and moral lessons."
+ },
+ {
+ "id": 14,
+ "name": "Fantasy",
+ "description": "Movies presenting a magical or fantastical world, often featuring supernatural elements, exotic creatures, and epic battles."
+ },
+ {
+ "id": 36,
+ "name": "History",
+ "description": "Movies exploring historical events, periods, or figures, often based on real facts and historical sources."
+ },
+ {
+ "id": 27,
+ "name": "Horror",
+ "description": "Movies intended to create fear and discomfort, often through supernatural events, monsters, and bloody scenes."
+ },
+ {
+ "id": 10402,
+ "name": "Music",
+ "description": "Movies focusing on music, musicians, or the music industry, often featuring musical performances and emotional themes."
+ },
+ {
+ "id": 9648,
+ "name": "Mystery",
+ "description": "Movies exploring secrets, unsolved puzzles, and unexplained events, often with surprising twists and revelations."
+ },
+ {
+ "id": 10749,
+ "name": "Romance",
+ "description": "Movies focusing on romantic relationships, love, and heartbreak, often with emotional conflicts and happy endings."
+ },
+ {
+ "id": 878,
+ "name": "Science Fiction",
+ "description": "Movies exploring future technology, space travel, alien life, and other scientific concepts."
+ },
+ {
+ "id": 10770,
+ "name": "TV Movie",
+ "description": "Movies specifically produced for television, often with a shorter runtime and smaller budget compared to theatrical films."
+ },
+ {
+ "id": 53,
+ "name": "Thriller",
+ "description": "Movies generating suspense, thrill, and tension, often through unexpected twists, threats, and dangerous situations."
+ },
+ {
+ "id": 10752,
+ "name": "War",
+ "description": "Movies depicting warfare, battles, and the impact of war on people and societies."
+ },
+ {
+ "id": 37,
+ "name": "Western",
+ "description": "Movies set in the American Wild West of the 19th century, often featuring cowboys, outlaws, and gunslingers."
+ },
+ {
+ "id": 0,
+ "name": "Unknown",
+ "description": "Oh, we don't know this genre! Feel free to send us a description 🎬🍿"
+ }
+ ]
+}
diff --git a/src/index.css b/src/index.css
index 4558f538..d5e24a65 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,13 +1,54 @@
:root {
- margin: 0;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
- "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
- sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
+ --font-color: white;
+ --primary-color: #111;
+ --secondary-color: #333;
+ --decor-color: #478c8c;
+ --box-shadow: rgba(0, 0, 0, 0.15) 0px 5px 15px 0px;
+ --text-shadow: rgba(0, 0, 0, 0.5) 0px 5px;
+ --text-backlit: rgba(255, 255, 255, 0.7) 0.2rem 0.2rem 1rem;
+
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-size: 16px;
+}
+
+@font-face {
+ font-family: Rubik Scribble;
+ src: url(./assets/RubikScribble-Regular.ttf);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ overflow-x: clip;
}
code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
- monospace;
+ /* For project instructions only */
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
+ monospace;
}
+
+body {
+ display: flex;
+ flex-direction: column;
+ background-color: var(--primary-color);
+ color: var(--font-color);
+}
+
+a {
+ color: var(--font-color);
+ text-decoration: none;
+ transition: all 0.2s ease-in;
+ cursor: pointer;
+}
+
+a:hover {
+ text-decoration: underline;
+ color: var(--decor-color);
+}
\ No newline at end of file