Adding UI functionality to the login view.
This commit is contained in:
parent
d50b3d2d41
commit
52aea274a7
@ -223,6 +223,30 @@ p {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shake {
|
||||||
|
animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
10%, 90% {
|
||||||
|
transform: translate3d(-1px, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
20%, 80% {
|
||||||
|
transform: translate3d(2px, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
30%, 50%, 70% {
|
||||||
|
transform: translate3d(-4px, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
40%, 60% {
|
||||||
|
transform: translate3d(4px, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Login text input styles. */
|
/* Login text input styles. */
|
||||||
@ -245,6 +269,9 @@ p {
|
|||||||
.loginField:focus {
|
.loginField:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
.loginField:disabled {
|
||||||
|
color: rgba(255, 255, 255, 0.50);
|
||||||
|
}
|
||||||
.loginField::-webkit-input-placeholder {
|
.loginField::-webkit-input-placeholder {
|
||||||
color: rgba(255, 255, 255, 0.75);
|
color: rgba(255, 255, 255, 0.75);
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
@ -321,6 +348,9 @@ p {
|
|||||||
#loginButton:active #loginSVG {
|
#loginButton:active #loginSVG {
|
||||||
-webkit-filter: drop-shadow(0px 0px 2px #c7c7c7);
|
-webkit-filter: drop-shadow(0px 0px 2px #c7c7c7);
|
||||||
}
|
}
|
||||||
|
#loginButton:disabled #loginSVG .arrowLine {
|
||||||
|
stroke: rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
#loginButtonContent {
|
#loginButtonContent {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -328,10 +358,10 @@ p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#loginButton .circle-loader,
|
#loginButton .circle-loader,
|
||||||
#loginButton:disabled #loginSVG {
|
#loginButton[loading] #loginSVG {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#loginButton:disabled .circle-loader,
|
#loginButton[loading] .circle-loader,
|
||||||
#loginButton #loginSVG {
|
#loginButton #loginSVG {
|
||||||
display: initial;
|
display: initial;
|
||||||
}
|
}
|
||||||
|
159
app/login.ejs
159
app/login.ejs
@ -9,7 +9,7 @@
|
|||||||
<path d="M86.77,58.12A13.79,13.79,0,1,0,73,71.91,13.79,13.79,0,0,0,86.77,58.12M97,103.67a3.41,3.41,0,0,0,3.39-3.84,27.57,27.57,0,0,0-54.61,0,3.41,3.41,0,0,0,3.39,3.84Z"/>
|
<path d="M86.77,58.12A13.79,13.79,0,1,0,73,71.91,13.79,13.79,0,0,0,86.77,58.12M97,103.67a3.41,3.41,0,0,0,3.39-3.84,27.57,27.57,0,0,0-54.61,0,3.41,3.41,0,0,0,3.39,3.84Z"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="loginErrorSpan" id="loginEmailError">* Invalid Email</span>
|
<span class="loginErrorSpan" id="loginEmailError">* Invalid Value</span>
|
||||||
<input id="loginUsername" class="loginField" type="text" placeholder="EMAIL"/>
|
<input id="loginUsername" class="loginField" type="text" placeholder="EMAIL"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="loginFieldContainer">
|
<div class="loginFieldContainer">
|
||||||
@ -26,12 +26,12 @@
|
|||||||
<a href="https://help.mojang.com/customer/en/portal/articles/329524-change-or-forgot-password">forgot password?</a>
|
<a href="https://help.mojang.com/customer/en/portal/articles/329524-change-or-forgot-password">forgot password?</a>
|
||||||
</span>
|
</span>
|
||||||
<label id="checkmarkContainer">
|
<label id="checkmarkContainer">
|
||||||
<input id="loginRememberOption" type="checkbox">
|
<input id="loginRememberOption" type="checkbox" checked>
|
||||||
<span id="loginRememberText" class="loginSpanDim">remember me?</span>
|
<span id="loginRememberText" class="loginSpanDim">remember me?</span>
|
||||||
<span class="loginCheckmark"></span>
|
<span class="loginCheckmark"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button id="loginButton">
|
<button id="loginButton" disabled>
|
||||||
<div id="loginButtonContent">
|
<div id="loginButtonContent">
|
||||||
LOGIN
|
LOGIN
|
||||||
<svg id="loginSVG" viewBox="0 0 24.87 13.97">
|
<svg id="loginSVG" viewBox="0 0 24.87 13.97">
|
||||||
@ -55,28 +55,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
|
||||||
//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
|
|
||||||
const loginUsername = document.getElementById('loginUsername')
|
|
||||||
const loginPassword = document.getElementById('loginPassword')
|
|
||||||
const checkmarkContainer = document.getElementById('checkmarkContainer')
|
|
||||||
const loginRememberOption = document.getElementById('loginRememberOption')
|
|
||||||
const loginButton = document.getElementById('loginButton')
|
|
||||||
loginButton.addEventListener('click', () => {
|
|
||||||
loginButton.disabled = true
|
|
||||||
loginUsername.disabled = true
|
|
||||||
loginPassword.disabled = true
|
|
||||||
checkmarkContainer.setAttribute('disabled', true)
|
|
||||||
loginRememberOption.disabled = true
|
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace('LOGIN', 'LOGGING IN')
|
|
||||||
setTimeout(() => {
|
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace('LOGGING IN', 'SUCCESS')
|
|
||||||
loginButton.style.color = '#ffffff'
|
|
||||||
$('.circle-loader').toggleClass('load-complete');
|
|
||||||
$('.checkmark').toggle();
|
|
||||||
}, 2500)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
<div id="loginErrorContainer">
|
<div id="loginErrorContainer">
|
||||||
<div id="loginErrorContent">
|
<div id="loginErrorContent">
|
||||||
<span id="loginErrorTitle">LOGIN FAILED:<br>INVALID CREDENTIALS</span>
|
<span id="loginErrorTitle">LOGIN FAILED:<br>INVALID CREDENTIALS</span>
|
||||||
@ -84,6 +62,137 @@
|
|||||||
<button id="loginErrorAcknowledge">Try Again</button>
|
<button id="loginErrorAcknowledge">Try Again</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="application/javascript">
|
||||||
|
//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
|
||||||
|
|
||||||
|
// Validation Regexes.
|
||||||
|
const validUsername = /^[a-zA-Z0-9_]{1,16}$/
|
||||||
|
const basicEmail = /^\S+@\S+\.\S+$/
|
||||||
|
|
||||||
|
// DOM cache.
|
||||||
|
const loginEmailError = document.getElementById('loginEmailError')
|
||||||
|
const loginUsername = document.getElementById('loginUsername')
|
||||||
|
const loginPasswordError = document.getElementById('loginPasswordError')
|
||||||
|
const loginPassword = document.getElementById('loginPassword')
|
||||||
|
const checkmarkContainer = document.getElementById('checkmarkContainer')
|
||||||
|
const loginRememberOption = document.getElementById('loginRememberOption')
|
||||||
|
const loginButton = document.getElementById('loginButton')
|
||||||
|
|
||||||
|
// Control variables.
|
||||||
|
let lu = false, lp = false
|
||||||
|
|
||||||
|
// Show error element.
|
||||||
|
function showError(element, value){
|
||||||
|
element.innerHTML = value
|
||||||
|
element.style.opacity = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shake error element.
|
||||||
|
function shakeError(element){
|
||||||
|
if(element.style.opacity == 1){
|
||||||
|
element.classList.remove('shake')
|
||||||
|
void element.offsetWidth
|
||||||
|
element.classList.add('shake')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate email field is neither empty nor invalid.
|
||||||
|
function validateEmail(value){
|
||||||
|
if(value){
|
||||||
|
if(!basicEmail.test(value) && !validUsername.test(value)){
|
||||||
|
showError(loginEmailError, '* Invalid Value')
|
||||||
|
loginDisabled(true)
|
||||||
|
lu = false
|
||||||
|
} else {
|
||||||
|
loginEmailError.style.opacity = 0
|
||||||
|
lu = true
|
||||||
|
if(lp){
|
||||||
|
loginDisabled(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lu = false
|
||||||
|
showError(loginEmailError, '* Required')
|
||||||
|
loginDisabled(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate password field is not empty.
|
||||||
|
function validatePassword(value){
|
||||||
|
if(value){
|
||||||
|
loginPasswordError.style.opacity = 0
|
||||||
|
lp = true
|
||||||
|
if(lu){
|
||||||
|
loginDisabled(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lp = false
|
||||||
|
showError(loginPasswordError, '* Required')
|
||||||
|
loginDisabled(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emphasize errors with shake when focus is lost.
|
||||||
|
loginUsername.addEventListener('focusout', (e) => {
|
||||||
|
validateEmail(e.target.value)
|
||||||
|
shakeError(loginEmailError)
|
||||||
|
})
|
||||||
|
loginPassword.addEventListener('focusout', (e) => {
|
||||||
|
validatePassword(e.target.value)
|
||||||
|
shakeError(loginPasswordError)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Validate input for each field.
|
||||||
|
loginUsername.addEventListener('input', (e) => {
|
||||||
|
validateEmail(e.target.value)
|
||||||
|
})
|
||||||
|
loginPassword.addEventListener('input', (e) => {
|
||||||
|
validatePassword(e.target.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Enable or disable login button.
|
||||||
|
function loginDisabled(v){
|
||||||
|
if(loginButton.disabled !== v){
|
||||||
|
loginButton.disabled = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable or disable loading elements.
|
||||||
|
function loginLoading(v){
|
||||||
|
loginButton.setAttribute('loading', v)
|
||||||
|
if(v){
|
||||||
|
loginButton.innerHTML = loginButton.innerHTML.replace('LOGIN', 'LOGGING IN')
|
||||||
|
} else {
|
||||||
|
loginButton.innerHTML = loginButton.innerHTML.replace('LOGGING IN', 'LOGIN')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable or enable login form.
|
||||||
|
function formDisabled(v){
|
||||||
|
loginDisabled(v)
|
||||||
|
loginUsername.disabled = true
|
||||||
|
loginPassword.disabled = true
|
||||||
|
checkmarkContainer.setAttribute('disabled', true)
|
||||||
|
loginRememberOption.disabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
loginButton.addEventListener('click', () => {
|
||||||
|
// Disable form.
|
||||||
|
formDisabled(true)
|
||||||
|
|
||||||
|
// Show loading stuff.
|
||||||
|
loginLoading(true)
|
||||||
|
|
||||||
|
// Temp for debugging, use procedure with real code.
|
||||||
|
setTimeout(() => {
|
||||||
|
loginButton.innerHTML = loginButton.innerHTML.replace('LOGGING IN', 'SUCCESS')
|
||||||
|
loginButton.style.color = '#ffffff'
|
||||||
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
|
$('.checkmark').toggle()
|
||||||
|
}, 2500)
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
<!-- Will reuse this down the line, then it will be removed from this file. -->
|
<!-- Will reuse this down the line, then it will be removed from this file. -->
|
||||||
<!--<div id="loginLoading">
|
<!--<div id="loginLoading">
|
||||||
<div id="loginLoadingContent">
|
<div id="loginLoadingContent">
|
||||||
|
Loading…
Reference in New Issue
Block a user