add loading and error handling for images

This commit is contained in:
andrzej 2024-05-16 13:49:58 +02:00
parent fc893a2584
commit 6d645c3dc0
4 changed files with 125 additions and 8 deletions

View File

@ -83,7 +83,7 @@ img {
figure {
width: 100%;
float: left;
margin: 0;
img {
aspect-ratio: 2/3;
@ -109,6 +109,9 @@ img {
grid-area: 1/1;
}
.highlighted {
border: 0.1em solid gold;
}
.overlay {
@ -121,10 +124,10 @@ img {
opacity: 0;
}
.highlighted>.overlay {
background-color: rgba(255, 222, 123, 0.5);
}
.overlay:hover {
opacity: 1;
}
.highlighted {
border: 0.1em solid gold;
}

View File

@ -1,5 +1,6 @@
import './defaults.css'
import './App.css'
import './spinner.css'
import { MovieWall } from './objects/movie-wall'
import { useState, useEffect } from 'react'
import tmdb from './objects/tmdb'

View File

@ -75,16 +75,24 @@ function Poster({ movie, config, listSimilar, setMovies, setChosenMovie, setSimi
setChosenMovie(movie)
listSimilar(config, movie, setMovies, setSimilarMoviesAvailable)
}
const [isLoading, setIsLoading] = useState(true)
const [hasError, setHasError] = useState(false)
const classes = [
"poster",
isHighlighted ? "highlighted" : ""
].join(" ")
return <div className={classes} >
<div className="overlay" onClick={() => clickHandler()}>
{isLoading ?
<div className="spinner-container">
<div className="lds-spinner"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div></div>
: <div className="overlay" onClick={() => clickHandler()}>
</div>
}
{hasError ?? <div className="spinner-container"></div>}
<img
src={tmdb.makeImgUrl(movie.poster_path ?? "")}
onLoad={() => console.log("LOADED IMG")}
onLoad={() => setIsLoading(false)}
onError={() => setHasError(true)}
/>
</div>
}

105
src/spinner.css Normal file
View File

@ -0,0 +1,105 @@
.spinner-container {
margin: auto;
text-align: center;
}
.lds-spinner,
.lds-spinner div,
.lds-spinner div:after {
box-sizing: border-box;
}
.lds-spinner {
color: currentColor;
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-spinner div {
transform-origin: 40px 40px;
animation: lds-spinner 1.2s linear infinite;
}
.lds-spinner div:after {
content: " ";
display: block;
position: absolute;
top: 3.2px;
left: 36.8px;
width: 6.4px;
height: 17.6px;
border-radius: 20%;
background: currentColor;
}
.lds-spinner div:nth-child(1) {
transform: rotate(0deg);
animation-delay: -1.1s;
}
.lds-spinner div:nth-child(2) {
transform: rotate(30deg);
animation-delay: -1s;
}
.lds-spinner div:nth-child(3) {
transform: rotate(60deg);
animation-delay: -0.9s;
}
.lds-spinner div:nth-child(4) {
transform: rotate(90deg);
animation-delay: -0.8s;
}
.lds-spinner div:nth-child(5) {
transform: rotate(120deg);
animation-delay: -0.7s;
}
.lds-spinner div:nth-child(6) {
transform: rotate(150deg);
animation-delay: -0.6s;
}
.lds-spinner div:nth-child(7) {
transform: rotate(180deg);
animation-delay: -0.5s;
}
.lds-spinner div:nth-child(8) {
transform: rotate(210deg);
animation-delay: -0.4s;
}
.lds-spinner div:nth-child(9) {
transform: rotate(240deg);
animation-delay: -0.3s;
}
.lds-spinner div:nth-child(10) {
transform: rotate(270deg);
animation-delay: -0.2s;
}
.lds-spinner div:nth-child(11) {
transform: rotate(300deg);
animation-delay: -0.1s;
}
.lds-spinner div:nth-child(12) {
transform: rotate(330deg);
animation-delay: 0s;
}
@keyframes lds-spinner {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}