This commit is contained in:
2024-03-01 15:39:57 +01:00
parent a13eba897c
commit f3da629131
83 changed files with 909 additions and 314 deletions

View File

@@ -0,0 +1,87 @@
main {
position: absolute;
top: 2rem;
left: 50%;
transform: translate(-50%, 0);
}
.loader {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.loader {
margin: 6rem 0 0;
}
.error {
color: #FFFAAA;
margin: 1rem 0;
}
label {
align-items: center;
display: flex;
flex-direction: column;
font-size: 1.6rem;
}
label span {
text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
}
input {
margin: 1rem 0 0;
font-size: 1.6rem;
font-weight: 300;
padding: 0.8rem 1rem;
color: white;
border: 1px solid rgba(255, 255, 255, 0.05);
background: rgba(255, 255, 255, 0.05);
transition: all 0.3s;
box-shadow: 1px 1px 2px rgba(0,0,0, 0.3);
-moz-appearance:none;
-webkit-appearance:none;
outline: none;
}
input:focus {
border: 1px solid transparent;
background: rgba(255, 255, 255, 0.08);
}
ul {
padding: 0;
margin: 1rem 0 2rem;
}
ul li {
padding: 0.6rem 1rem;
margin: 1px 0;
line-height: 1.4rem;
display: flex;
justify-content: space-between;
align-items: center;
align-content: space-between;
text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
background: rgba(255, 255, 255, 0.08);
box-shadow: 0 0 2px rgba(0,0,0, 0.3);
box-sizing: border-box;
}
ul li:hover,
ul li:active,
ul li:focus {
background: rgba(255, 255, 255, 0.1);
}
ul li a {
margin: 0 0.6rem 0 0;
text-decoration: none;
color: white;
}
ul li span {
opacity: 0.5;
}
body {
margin: 0;
font-family: 'Helvetica Neue', Helvetica, Arial;
font-weight: 300;
background-size: cover;
background-attachment: fixed;
background-image: -webkit-radial-gradient(ellipse farthest-corner at top, #661141, #000000);
background-image: radial-gradient(ellipse farthest-corner at top, #661141, #000000);
color: white;
}

View File

@@ -0,0 +1,13 @@
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg width="44" height="44" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
<g fill="none" fill-rule="evenodd" stroke-width="2">
<circle cx="22" cy="22" r="1">
<animate attributeName="r" begin="0s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite"/>
<animate attributeName="stroke-opacity" begin="0s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite"/>
</circle>
<circle cx="22" cy="22" r="1">
<animate attributeName="r" begin="-0.9s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite"/>
<animate attributeName="stroke-opacity" begin="-0.9s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite"/>
</circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

28
DEV4.1/tp4/ex1/index.html Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1,witdh=device-width">
<link rel="stylesheet" type="text/css" href="./css/style.css">
</head>
<body>
<!-- vue html -->
<main>
<label>
<span>Search a movie</span>
<input type="input" placeholder="28 Days Later..">
</label>
<div class="loader">
<img src="./img/puff.svg">
</div>
<p class="error"></p>
<div id="list-movies">
</div>
</main>
</body>
<script type="module" src="./js/app.js"></script>
</html>

7
DEV4.1/tp4/ex1/js/app.js Normal file
View File

@@ -0,0 +1,7 @@
import model from './model'
import Controller from './controller'
import View from './view'
const view = new View()
const app = new Controller(view,model)

View File

@@ -0,0 +1,45 @@
class Controller {
constructor(view,model){
this.view = view
this.model = model
this.loading = false
this.lastSearch = null
this.error = null
this.results = []
this.view.setLoading(false)
this.view.bindSearch(this.search.bind(this))
}
reset() {
this.loading = false
this.error = null
this.results = []
}
async search(searchMovie) {
try {
this.reset();
this.loading = true;
this.view.setLoading(true);
const movies = await this.model.getMovies(searchMovie);
if (movies && movies.length > 0) {
this.results = movies;
} else {
this.error = "No movies found.";
}
} catch (error) {
console.error('Error occurred during search:', error);
this.error = "An error occurred during search.";
} finally {
this.loading = false;
this.view.setLoading(false);
this.view.renderResults(this.results, this.error);
}
}
}
export default Controller

View File

@@ -0,0 +1,12 @@
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds.
function debounce(fn, wait) {
let timeout
return (...args) => {
clearTimeout(timeout)
timeout = setTimeout(() => fn(...args), wait)
}
}
export default debounce

View File

@@ -0,0 +1,23 @@
let apiKey = 'a776e2df'
let model = {
getMovies(search){
return new Promise((resolve, reject) => {
fetch(`http://www.omdbapi.com/?apikey=${apiKey}&s=${search}`)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
resolve(data.Search);
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);}
)
})
}
}
export default model

54
DEV4.1/tp4/ex1/js/view.js Normal file
View File

@@ -0,0 +1,54 @@
import debounce from "./helpers.js"
class View {
constructor(){
this.listMovies = document.querySelector("#list-movies")
this.inputSearch = document.querySelector("input")
this.loader = document.querySelector(".loader")
this.message = document.querySelector("p.error")
}
_getInput(){
return this.inputSearch.value
}
setLoading(loading){
if (loading)
this.loader.style.display = "block"
else
this.loader.style.display = "none"
}
renderMessage(error){
this.message.style.display = "block"
this.message.textContent = error
}
renderList(movies){
let ul = document.createElement("ul")
movies.forEach((movie)=>{
let li = document.createElement("li")
let a = document.createElement("a")
let span = document.createElement("span")
a.href = `http://www.imdb.com/title/${movie.imdbID}`
a.target="_blank"
a.textContent = movie.Title
span.textContent = movie.Year
li.appendChild(a)
li.appendChild(span)
ul.appendChild(li)
})
this.listMovies.replaceChildren(ul)
}
bindSearch(handler){
this.inputSearch.addEventListener("input",debounce((e)=>{
handler(this._getInput())
},500))
}
}
export default View