feat(DevWeb): Add icons

This commit is contained in:
Lucàs
2024-04-20 21:19:56 +02:00
parent b36e5e1041
commit 8e954a0656
5 changed files with 199 additions and 302 deletions
@@ -22,10 +22,20 @@
User user = (User) session.getAttribute("user");
%>
<div class="navbar-item">
<a href="${pageContext.request.contextPath}/profile" class="is-fullwidth button is-light"><%= user.getUsername() %></a>
<a href="${pageContext.request.contextPath}/profile" class="is-fullwidth button is-light">
<span class="icon">
<i class="fa-solid fa-user"></i>
</span>
<span><%= user.getUsername() %></span>
</a>
</div>
<div class="navbar-item">
<a href="${pageContext.request.contextPath}/logout" class="is-fullwidth button is-light is-danger">Déconnexion</a>
<a href="${pageContext.request.contextPath}/logout" class="is-fullwidth button is-light is-danger">
<span class="icon">
<i class="fa-solid fa-door-open"></i>
</span>
<span>Déconnexion</span>
</a>
</div>
<% } else {%>
@@ -33,7 +43,12 @@
<a href="${pageContext.request.contextPath}/register" class="is-fullwidth button is-primary has-text-white">Inscription</a>
</div>
<div class="navbar-item">
<a href="${pageContext.request.contextPath}/login" class="is-fullwidth button is-light">Connexion</a>
<a href="${pageContext.request.contextPath}/login" class="is-fullwidth button is-light">
<span class="icon">
<i class="fa-solid fa-right-to-bracket"></i>
</span>
<span>Connexion</span>
</a>
</div>
<% } %>
</div>
@@ -3,55 +3,17 @@
<form id="forgotten-password-form" action="${pageContext.request.contextPath}/forgotten-password" method="post">
<div class="field"> <!-- Field Username -->
<label class="label" for="email">Email</label>
<input id="email" placeholder="johndoe@exemple.com" class="input is-fullwidth" required/>
<div class="control has-icons-left">
<input id="email" placeholder="johndoe@exemple.com" class="input is-fullwidth" required/>
<span class="icon is-small is-left">
<i class="fas fa-envelope"></i>
</span>
</div>
<div class="help">Veuillez entrer votre email pour obtenir un lien de récupération</div>
</div>
<input type="submit" class="button is-primary is-fullwidth" value="Envoyer">
<input type="submit" class="button is-primary is-fullwidth has-text-white" value="Envoyer">
</form>
<style>
.notification {
position: absolute;
bottom: 0;
right: 0;
margin: 1em !important;
transform: translateY(100%);
opacity: 0;
animation: toast 5s ease forwards;
}
@keyframes toast {
0% {
opacity: 0;
transform: translateY(100%);
}
5% {
opacity: 1;
transform: translateY(0);
}
95% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(100%);
}
}
@keyframes shake {
0%, 100% {
transform: translateX(0);
}
10%, 30%, 50%, 70%, 90% {
transform: translateX(-5px);
}
20%, 40%, 60%, 80% {
transform: translateX(5px);
}
}
</style>
<script defer type="module">
const forgottenPasswordForm = document.querySelector("form#forgotten-password-form");
@@ -1,88 +1,47 @@
<%@tag description="form/login" pageEncoding="UTF-8" %>
<form id="login-form" action="${pageContext.request.contextPath}/login" method="post">
<div class="field"> <!-- Field Username -->
<label class="label" for="username">Nom d'utilisateur</label>
<input id="username" placeholder="John Doe" class="input is-fullwidth" required/>
</div>
<div class="field"> <!-- Field Password -->
<label class="label" for="password">Mot de passe</label>
<input id="password" class="input is-fullwidth" type="password" required/>
</div>
<p class="content has-text-right"><a href="${pageContext.request.contextPath}/forgotten-password" class="link">Mot de passe oublié ?</a>
</p>
<input type="submit" class="button is-primary has-text-white is-fullwidth" value="Connexion">
<hr/>
<p class="content has-text-centered"><a href="${pageContext.request.contextPath}/register">S'inscrire</a></p>
<!-- Field Username -->
<div class="field">
<label class="label" for="username">Nom d'utilisateur</label>
<div class="control has-icons-left">
<input id="username" name="username" placeholder="John Doe" type="text" class="input is-fullwidth" required/>
<span class="icon is-left">
<i class="fas fa-user"></i>
</span>
</div>
</div>
<!-- Field Password -->
<div class="field">
<label class="label" for="password">Mot de passe</label>
<div class="control has-icons-left">
<input id="password" name="password" placeholder="Mot de passe" class="input is-fullwidth" type="password" required/>
<span class="icon is-left">
<i class="fas fa-lock"></i>
</span>
</div>
</div>
<p class="content has-text-right">
<a href="${pageContext.request.contextPath}/forgotten-password" class="link">Mot de passe oublié ?</a>
</p>
<input type="submit" class="button is-primary has-text-white is-fullwidth" value="Connexion">
</form>
<style>
.notification {
position: absolute;
bottom: 0;
right: 0;
margin: 1em !important;
transform: translateY(100%);
opacity: 0;
animation: toast 5s ease forwards;
}
@keyframes toast {
0% {
opacity: 0;
transform: translateY(100%);
}
5% {
opacity: 1;
transform: translateY(0);
}
95% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(100%);
}
}
@keyframes shake {
0%, 100% {
transform: translateX(0);
}
10%, 30%, 50%, 70%, 90% {
transform: translateX(-5px);
}
20%, 40%, 60%, 80% {
transform: translateX(5px);
}
}
</style>
<script defer type="module">
const loginForm = document.querySelector("form#login-form");
const form = document.querySelector("form#login-form");
const inputs = form.querySelectorAll("input[type='text'], input[type='password']");
// Form fields
const usernameInput = document.querySelector("input#username");
const passwordInput = document.querySelector("input#password");
// Add event listener to the form submission
loginForm.addEventListener("submit", onSubmit)
/**
* Handle the form submission with Ajax request
* @param event {Event} - Event of the form submission
*/
function onSubmit(event) {
form.addEventListener("submit", event => {
event.preventDefault();
const {action, method} = loginForm;
const {action, method} = form;
const url = new URL(action);
url.searchParams.append("username", usernameInput.value);
url.searchParams.append("password", passwordInput.value);
inputs.forEach(input => url.searchParams.append(input.getAttribute("name"), input.value));
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
@@ -90,34 +49,42 @@
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = "${pageContext.request.contextPath}/main-menu")
.catch(onError);
}
.catch((error) => {
console.log(error)
/**
* Handle the error of the form submission
* @param error {Error} - Error of the form submission
*/
function onError(error) {
console.error("Error:", error)
// Input animation
inputs.forEach(input => {
input.classList.add("is-danger");
input.style.animation = "shake 0.5s ease-in-out"
});
// Input fields in red
usernameInput.classList.add("is-danger");
passwordInput.classList.add("is-danger");
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
// Shake the inputs
usernameInput.style.animation = "shake 0.5s ease-in-out";
passwordInput.style.animation = "shake 0.5s ease-in-out";
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
notification.innerHTML = error.message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
// Remove the shake animation at the end of animation
usernameInput.addEventListener("animationend", () => usernameInput.style.animation = "");
passwordInput.addEventListener("animationend", () => passwordInput.style.animation = "");
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
// Remove notification and animation after 5s
setTimeout(() => notification.remove(), 5010);
});
});
// On animation end, remove class and animation
inputs.forEach(input => input.addEventListener("animationend", () => input.style.animation = ""));
</script>
@@ -3,22 +3,34 @@
<form id="register-form" action="${pageContext.request.contextPath}/register" method="post">
<div class="field">
<label class="label" for="username">Nom d'utilisateur</label>
<input id="username" name="username" placeholder="John Doe" type="text" class="input is-fullwidth" required>
<div class="control has-icons-left">
<input id="username" name="username" placeholder="John Doe" type="text" class="input is-fullwidth" required>
<span class="icon is-left"><i class="fas fa-user"></i></span>
</div>
</div>
<div class="field">
<label class="label" for="email">Email</label>
<input id="email" name="email" type="email" placeholder="johndoe@exemple.com" class="input is-fullwidth" required>
<div class="control has-icons-left">
<input id="email" name="email" type="email" placeholder="johndoe@exemple.com" class="input is-fullwidth" required>
<span class="icon is-left"><i class="fas fa-envelope"></i></span>
</div>
</div>
<div class="field">
<label class="label" for="password">Mot de passe</label>
<input id="password" name="password" type="password" class="input is-fullwidth" required>
<div class="control has-icons-left">
<input id="password" name="password" placeholder="Mot de passe" type="password" class="input is-fullwidth" required>
<span class="icon is-left"><i class="fas fa-lock"></i></span>
</div>
</div>
<div class="field">
<label class="label" for="repassword">Confirmez le mot de passe</label>
<input id="repassword" name="repassword" type="password" class="input is-fullwidth" required>
<div class="control has-icons-left">
<input id="repassword" name="repassword" placeholder="Répétez le mot de passe" type="password" class="input is-fullwidth" required>
<span class="icon is-left"><i class="fas fa-lock"></i></span>
</div>
</div>
<div class="field">
@@ -28,65 +40,27 @@
<div class="field">
<label class="label" for="gender">Genre</label>
<div class="select is-fullwidth">
<select name="gender" id="gender" required>
<option selected value="">--Choisissez une option--</option>
<option value="MALE">Homme</option>
<option value="FEMALE">Femme</option>
<option value="OTHER">Autre</option>
</select>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select name="gender" id="gender" required>
<option selected value="">- Choisissez une option -</option>
<option value="MALE">Homme</option>
<option value="FEMALE">Femme</option>
<option value="OTHER">Autre</option>
</select>
</div>
<span class="icon is-left"><i class="fa-solid fa-venus-mars"></i></span>
</div>
</div>
<input type="submit" class="button has-text-white is-primary is-fullwidth" value="S'inscrire">
<hr/>
<p class="content has-text-centered">Déjà inscrit ? <a href="${pageContext.request.contextPath}/login">Se connecter</a></p>
</form>
<style>
.notification {
position: absolute;
bottom: 0;
right: 0;
margin: 1em !important;
max-width: 40em;
transform: translateY(100%);
opacity: 0;
animation: toast 5s ease forwards;
}
@keyframes toast {
0% {
opacity: 0;
transform: translateY(100%);
}
5% {
opacity: 1;
transform: translateY(0);
}
95% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(100%);
}
}
</style>
<script defer type="module">
const registerForm = document.querySelector("form#register-form");
// Form fields
const usernameInput = document.querySelector("input#username");
const emailInput = document.querySelector("input#email");
const passwordInput = document.querySelector("input#password");
const repasswordInput = document.querySelector("input#repassword");
const birthInput = document.querySelector("input#birth");
const genderInput = document.querySelector("select#gender");
const submitButton = document.querySelector("input[type=submit]");
const inputs = registerForm.querySelectorAll("input, select");
// Add event listener to the form submission
registerForm.addEventListener("submit", onSubmit)
@@ -98,8 +72,11 @@
function onSubmit(event) {
event.preventDefault();
const password = registerForm.querySelector("input[name='password']");
const repassword = registerForm.querySelector("input[name='repassword']");
// Check if the password and the confirmation password are the same
if (passwordInput.value !== repasswordInput.value) {
if (password.value !== repassword.value) {
onError(new Error("Les mots de passe ne correspondent pas"));
return;
}
@@ -107,13 +84,8 @@
const {action, method} = registerForm;
const url = new URL(action);
url.searchParams.append("username", usernameInput.value);
url.searchParams.append("email", emailInput.value);
url.searchParams.append("password", passwordInput.value);
url.searchParams.append("birth", birthInput.value);
url.searchParams.append("gender", genderInput.value);
inputs.forEach(input => url.searchParams.append(input.name, input.value));
submitButton.classList.add("is-loading");
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
@@ -121,7 +93,6 @@
})
.then(() => window.location.href = "${pageContext.request.contextPath}/login")
.catch(onError)
.finally(() => submitButton.classList.remove("is-loading"));
}
/**
@@ -132,18 +103,29 @@
console.error("Error:", error)
// Input fields in red
usernameInput.classList.add("is-danger");
emailInput.classList.add("is-danger");
passwordInput.classList.add("is-danger");
repasswordInput.classList.add("is-danger");
birthInput.classList.add("is-danger");
genderInput.classList.add("is-danger");
inputs.forEach(input => input.classList.add("is-danger"));
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
notification.innerHTML = error.message;
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
</script>
@@ -4,111 +4,82 @@
<input type="hidden" id="token" name="token" value="${pageContext.request.getParameter("token")}">
<div class="field">
<label class="label" for="password">Mot de passe</label>
<input id="password" name="password" type="password" class="input is-fullwidth" required>
<div class="control has-icons-left">
<input id="password" name="password" type="password" class="input is-fullwidth" required>
<span class="icon is-small is-left"><i class="fas fa-lock"></i></span>
</div>
</div>
<div class="field">
<label class="label" for="repassword">Confirmez le mot de passe</label>
<input id="repassword" name="repassword" type="password" class="input is-fullwidth" required>
<div class="control has-icons-left">
<input id="repassword" name="repassword" type="password" class="input is-fullwidth" required>
<span class="icon is-small is-left"><i class="fas fa-lock"></i></span>
</div>
</div>
<input type="submit" class="button is-primary is-fullwidth" value="Envoyer">
<hr/>
<p class="content has-text-centered">Déjà inscrit ? <a href="${pageContext.request.contextPath}/login">Se connecter</a></p>
</form>
<style>
.notification {
position: absolute;
bottom: 0;
right: 0;
margin: 1em !important;
max-width: 40em;
transform: translateY(100%);
opacity: 0;
animation: toast 5s ease forwards;
}
@keyframes toast {
0% {
opacity: 0;
transform: translateY(100%);
}
5% {
opacity: 1;
transform: translateY(0);
}
95% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(100%);
}
}
</style>
<script defer type="module">
const resetPasswordForm = document.querySelector("form#reset-password-form");
const submitButton = document.querySelector("input[type=submit]");
const resetPasswordForm = document.querySelector("form#reset-password-form");
const submitButton = document.querySelector("input[type=submit]");
// Form fields
const tokenInput = document.querySelector("input#token");
const passwordInput = document.querySelector("input#password");
const repasswordInput = document.querySelector("input#repassword");
// Form fields
const tokenInput = document.querySelector("input#token");
const passwordInput = document.querySelector("input#password");
const repasswordInput = document.querySelector("input#repassword");
// Add event listener to the form submission
resetPasswordForm.addEventListener("submit", onSubmit)
// Add event listener to the form submission
resetPasswordForm.addEventListener("submit", onSubmit)
/**
* Handle the form submission with Ajax request
* @param event {Event} - Event of the form submission
*/
function onSubmit(event) {
event.preventDefault();
/**
* Handle the form submission with Ajax request
* @param event {Event} - Event of the form submission
*/
function onSubmit(event) {
event.preventDefault();
// Check if the password and the confirmation password are the same
if (passwordInput.value !== repasswordInput.value) {
onError(new Error("Les mots de passe ne correspondent pas"));
return;
// Check if the password and the confirmation password are the same
if (passwordInput.value !== repasswordInput.value) {
onError(new Error("Les mots de passe ne correspondent pas"));
return;
}
const {action, method} = resetPasswordForm;
const url = new URL(action);
url.searchParams.append("token", tokenInput.value);
url.searchParams.append("password", passwordInput.value);
submitButton.classList.add("is-loading");
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = "${pageContext.request.contextPath}/login")
.catch(onError)
.finally(() => submitButton.classList.remove("is-loading"));
}
const {action, method} = resetPasswordForm;
/**
* Handle the error of the form submission
* @param error {Error} - Error of the form submission
*/
function onError(error) {
console.error("Error:", error)
const url = new URL(action);
url.searchParams.append("token", tokenInput.value);
url.searchParams.append("password", passwordInput.value);
// Input fields in red
passwordInput.classList.add("is-danger");
repasswordInput.classList.add("is-danger");
submitButton.classList.add("is-loading");
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = "${pageContext.request.contextPath}/login")
.catch(onError)
.finally(() => submitButton.classList.remove("is-loading"));
}
/**
* Handle the error of the form submission
* @param error {Error} - Error of the form submission
*/
function onError(error) {
console.error("Error:", error)
// Input fields in red
passwordInput.classList.add("is-danger");
repasswordInput.classList.add("is-danger");
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
notification.innerHTML = error.message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
notification.innerHTML = error.message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
</script>