This commit is contained in:
andrzej 2024-05-05 23:59:33 +02:00
parent 5d6eaee4ba
commit da61b72402
7 changed files with 195 additions and 55 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ dist-ssr
*.sln *.sln
*.sw? *.sw?
src/conf.js src/conf.js
src/auth.json

View File

@ -1,42 +1,41 @@
#root { .flow-container {
max-width: 1280px; display: flex;
margin: 0 auto; flex-wrap: wrap;
padding: 2rem; width: 80%;
text-align: center; margin: auto;
} }
.logo { .poster {
height: 6em; font-size: 2rem;
padding: 1.5em; aspect-ratio: 3/4.5;
will-change: filter; width: 25rem;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
} }
@keyframes logo-spin {
from {
transform: rotate(0deg); .overlay {
margin: 0;
height: 100%;
width: 100%;
font-size: inherit;
color: white;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
p {
font-size: 0.8em;
} }
to {
transform: rotate(360deg); h1 {
font-size: 1.6em;
margin: 0;
} }
} }
@media (prefers-reduced-motion: no-preference) { .overlay:hover {
a:nth-of-type(2) .logo { opacity: 1;
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
} }

View File

@ -1,3 +1,4 @@
import './defaults.css'
import './App.css' import './App.css'
import { MovieWall } from './objects/movie-wall' import { MovieWall } from './objects/movie-wall'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
@ -11,11 +12,12 @@ export type Config = {
function App() { function App() {
const [config, setConfig] = useState<Config>({ const [config, setConfig] = useState<Config>({
language: "es", language: "es",
region: "spain" region: "spain",
page: 1
}) })
const [popularMovies, setPopularMovies] = useState([]) const [movies, setMovies] = useState([])
useEffect(() => { tmdb.getPopular(config, setPopularMovies) }, []) useEffect(() => { tmdb.getPopular(config, setMovies) }, [])
useEffect(() => { console.log(popularMovies) }, [popularMovies]) useEffect(() => { console.log(movies) }, [movies])
return ( return (
<> <>
<header> <header>
@ -23,7 +25,9 @@ function App() {
</header> </header>
<main> <main>
Let's explore! Let's explore!
<MovieWall movies={popularMovies} /> <div className='flow-container'>
<MovieWall movies={movies} setMovies={setMovies} />
</div>
</main> </main>
</> </>

62
src/defaults.css Normal file
View File

@ -0,0 +1,62 @@
*,
*::before,
*::after {
box-sizing: border-box;
}
img {
display: block;
max-width: 100%;
}
menu:not(article menu),
ol:not(article ol),
ul:not(article ul) {
list-style: none;
}
menu,
ol,
ul {
padding-left: 0;
}
article ol,
article ul {
list-style-position: inside;
}
a {
/* Places underlines below the descenders */
text-underline-position: under;
/* Sets the thickness as a percentage of the font size */
text-decoration-thickness: 8;
}
/* <html> = the root */
html {
font-size: 62.5%;
/* (62.5/100) * 16px = 10px */
-webkit-text-size-adjust: none;
/* for iOS Safari */
text-size-adjust: none;
/* for other mobile browsers */
}
@media (prefers-reduced-motion: no-preference) {
html {
scroll-behavior: smooth;
}
}
label,
button,
select,
summary,
[type=radio],
[type=submit],
[type=checkbox] {
cursor: pointer;
}

19
src/functions.tsx Normal file
View File

@ -0,0 +1,19 @@
/**
* Move array item from provided index to specified index
* @remarks 'to' index refers to position in original array, i.e. if to > from, to = to -1
* @param array
* @param from - the index of the item we want moved
* @param to - the index we want the item moved to
* @returns The modified array
*
* @beta
*/
export function relocateArrayItem(array: Array<any>, from: number, to: number) {
const newArray = structuredClone(array)
const element = newArray.splice(from, 1)[0]
newArray.splice(to < from ? to : to - 1, 0, element)
console.log("reordered array: ")
console.log(newArray)
return newArray
}

View File

@ -1,4 +1,5 @@
import { FC } from "react" import React, { useState } from "react"
import { relocateArrayItem } from "../functions"
type Movie = { type Movie = {
id: string id: string
@ -24,17 +25,27 @@ const sampleData = {
vote_count: 52 vote_count: 52
} }
interface MovieWallProps extends React.ComponentPropsWithRef<"div"> {
movies: Array<Movie>;
setMovies: Function;
}
export const MovieWall: FC<{ movies: Array<Movie> }> = (props) => { export function MovieWall({ movies, setMovies }: MovieWallProps) {
const movies = props.movies
function moveMovieToFront(index: number) {
setMovies((prev: Array<Movie>) => { return relocateArrayItem(prev, index, 0) })
}
function listSimilarMovies(movie: Movie) {
}
const posters = [] const posters: Array<React.Component> = []
for (let i = 0; i < movies.length; i++) { for (let i = 0; i < movies.length; i++) {
const movie = movies[i] const movie = movies[i]
posters.push( posters.push(
<Poster movie={movie} /> <Poster movie={movie} key={movie.id} index={i} moveMovieToFront={moveMovieToFront} />
) )
} }
return <> return <>
@ -42,15 +53,26 @@ export const MovieWall: FC<{ movies: Array<Movie> }> = (props) => {
</> </>
} }
type PosterProps = { interface PosterProps extends React.ComponentPropsWithRef<"div"> {
movie: Movie; movie: Movie;
moveMovieToFront: Function;
index: number;
} }
function Poster({ movie }: PosterProps) {
return <a href={"https://www.themoviedb.org/movie/" + movie.id}> function Poster({ movie, index, moveMovieToFront: onclick }: PosterProps) {
<h1>{movie.title}</h1> const [style, setStyle] = useState({
<p>{movie.overview}</p> backgroundImage: "url(https://image.tmdb.org/t/p/w500/" + movie.poster_path + ")",
<img src={"https://image.tmdb.org/t/p/w500/" + movie.poster_path} /> backgroundSize: "cover",
</a> alignSelf: "auto",
color: "inherit"
})
return <div className="poster" style={style}>
<div className="overlay" onClick={() => { onclick(index) }}>
<h1>{movie.title}</h1>
<p>{movie.overview}</p>
</div>
</div>
} }

View File

@ -10,15 +10,48 @@ const tmdb = axios.create({
} }
}) })
export default { export default {
getPopular: async function({ language, region }: Config, callback: Function) { /**
let res = await tmdb.get('/popular?language=en-US&page=1', * Calls tmdb API/popular and then fires the callback with res.data.results as argument
* @param {Function} callback
* @returns {boolean}
*/
getPopular: async function({ language, region, page }: Config, callback: Function) {
let res = await tmdb.get('/popular',
{ {
params: { params: {
language, language,
region region,
page
} }
}) })
res = res.data.results console.log(res)
callback(res) if (res.status === 200) {
res = res.data.results
callback(res)
return true
} else {
throw Error("API call failed! Response: " + JSON.stringify(res))
}
},
/**
* Calls TMDB/similar
*/
getSimilar: async function({ language, page }: Config, id: number, callback: Function) {
let res = await tmdb.get(id + '/similar', {
params: {
language,
page
}
})
console.log(res)
if (res.status === 200) {
res = res.data.results
callback(res)
return true
} else {
throw Error("API call failed! Response: " + JSON.stringify(res))
}
} }
} }