Explorar o código

Adding UI functionality to the login view.

Daniel Scalzi %!s(int64=7) %!d(string=hai) anos
pai
achega
52aea274a7
Modificáronse 2 ficheiros con 157 adicións e 18 borrados
  1. 32 2
      app/assets/css/launcher.css
  2. 125 16
      app/login.ejs

+ 32 - 2
app/assets/css/launcher.css

@@ -223,6 +223,30 @@ p {
     text-align: right;
     position: absolute;
     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. */
@@ -245,6 +269,9 @@ p {
 .loginField:focus {
     outline: none;
 }
+.loginField:disabled {
+    color: rgba(255, 255, 255, 0.50);
+}
 .loginField::-webkit-input-placeholder {
     color: rgba(255, 255, 255, 0.75);
     font-size: 10px;
@@ -321,6 +348,9 @@ p {
 #loginButton:active #loginSVG {
     -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7);
 }
+#loginButton:disabled #loginSVG .arrowLine {
+    stroke: rgba(255, 255, 255, 0.75);
+}
 
 #loginButtonContent {
     display: flex;
@@ -328,10 +358,10 @@ p {
 }
 
 #loginButton .circle-loader,
-#loginButton:disabled #loginSVG {
+#loginButton[loading] #loginSVG {
     display: none;
 }
-#loginButton:disabled .circle-loader,
+#loginButton[loading] .circle-loader,
 #loginButton #loginSVG {
     display: initial;
 }

+ 125 - 16
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"/>
                     </g>
                 </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"/>
             </div>
             <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>
                 </span>
                 <label id="checkmarkContainer">
-                    <input id="loginRememberOption" type="checkbox">
+                    <input id="loginRememberOption" type="checkbox" checked>
                     <span id="loginRememberText" class="loginSpanDim">remember me?</span>
                     <span class="loginCheckmark"></span>
                 </label>
             </div>
-            <button id="loginButton">
+            <button id="loginButton" disabled>
                 <div id="loginButtonContent">
                     LOGIN
                     <svg id="loginSVG" viewBox="0 0 24.87 13.97">
@@ -55,35 +55,144 @@
             </div>
         </div>
     </div>
-    <script type="text/javascript">
+    <div id="loginErrorContainer">
+        <div id="loginErrorContent">
+            <span id="loginErrorTitle">LOGIN FAILED:<br>INVALID CREDENTIALS</span>
+            <span id="loginErrorDesc">Either the email or password you supplied is invalid. Please ensure everything is correct and try again.</span>
+            <button id="loginErrorAcknowledge">Try Again</button>
+        </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')
-        loginButton.addEventListener('click', () => {
-            loginButton.disabled = true
+
+        // 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.innerHTML = loginButton.innerHTML.replace('LOGIN', 'LOGGING IN')
+        }
+
+        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();
+                $('.circle-loader').toggleClass('load-complete')
+                $('.checkmark').toggle()
             }, 2500)
+
         })
     </script>
-    <div id="loginErrorContainer">
-        <div id="loginErrorContent">
-            <span id="loginErrorTitle">LOGIN FAILED:<br>INVALID CREDENTIALS</span>
-            <span id="loginErrorDesc">Either the email or password you supplied is invalid. Please ensure everything is correct and try again.</span>
-            <button id="loginErrorAcknowledge">Try Again</button>
-        </div>
-    </div>
     <!-- Will reuse this down the line, then it will be removed from this file. -->
     <!--<div id="loginLoading">
         <div id="loginLoadingContent">