diff options
| -rwxr-xr-x | app/assets/images/icon-arrow-active.svg | 7 | ||||
| -rwxr-xr-x | app/assets/images/icon-arrow-inactive.svg | 7 | ||||
| -rw-r--r-- | app/components/Login.css | 49 | ||||
| -rw-r--r-- | app/components/Login.js | 59 |
4 files changed, 110 insertions, 12 deletions
diff --git a/app/assets/images/icon-arrow-active.svg b/app/assets/images/icon-arrow-active.svg new file mode 100755 index 0000000000..9e5674866f --- /dev/null +++ b/app/assets/images/icon-arrow-active.svg @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="24px" height="16px" viewBox="0 0 24 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>icon-arrow</title> + <desc>Mullvad VPN app</desc> + <defs></defs> + <path fill="#294D73" d="M18.7015867,9 L14.4331381,12.762659 C13.851665,13.2752305 13.8579999,14.1003943 14.4392669,14.612784 C15.0245863,15.1287461 15.9602099,15.1275926 16.5380921,14.6181865 L23.5668627,8.42228969 C23.8565791,8.16690324 24.000373,7.83391619 23.999837,7.50067932 L24,7.4966702 C23.999589,7.16348359 23.8547954,6.83138119 23.5668627,6.57756713 L16.5380921,0.381670278 C15.956619,-0.130901228 15.0205338,-0.125317014 14.4392669,0.387072772 C13.8539474,0.903034846 13.8552559,1.72779176 14.4331381,2.23719784 L18.7017491,6 L1.50909424,6 C0.66354084,6 0,6.67157288 0,7.5 C0,8.33420277 0.675644504,9 1.50909424,9 L18.7015867,9 Z" id="icon-arrow"></path> +</svg>
\ No newline at end of file diff --git a/app/assets/images/icon-arrow-inactive.svg b/app/assets/images/icon-arrow-inactive.svg new file mode 100755 index 0000000000..69c7339bc0 --- /dev/null +++ b/app/assets/images/icon-arrow-inactive.svg @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="24px" height="16px" viewBox="0 0 24 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>icon-arrow</title> + <desc>Mullvad VPN app</desc> + <defs></defs> + <path fill="rgba(41,77,115,0.2)" d="M18.7015867,9 L14.4331381,12.762659 C13.851665,13.2752305 13.8579999,14.1003943 14.4392669,14.612784 C15.0245863,15.1287461 15.9602099,15.1275926 16.5380921,14.6181865 L23.5668627,8.42228969 C23.8565791,8.16690324 24.000373,7.83391619 23.999837,7.50067932 L24,7.4966702 C23.999589,7.16348359 23.8547954,6.83138119 23.5668627,6.57756713 L16.5380921,0.381670278 C15.956619,-0.130901228 15.0205338,-0.125317014 14.4392669,0.387072772 C13.8539474,0.903034846 13.8552559,1.72779176 14.4331381,2.23719784 L18.7017491,6 L1.50909424,6 C0.66354084,6 0,6.67157288 0,7.5 C0,8.33420277 0.675644504,9 1.50909424,9 L18.7015867,9 Z" id="icon-arrow"></path> +</svg>
\ No newline at end of file diff --git a/app/components/Login.css b/app/components/Login.css index 3b46310078..9417dc5537 100644 --- a/app/components/Login.css +++ b/app/components/Login.css @@ -72,13 +72,21 @@ .login-form__input-wrap { border: 4px solid rgba(0,0,0,0.1); + background-color: #FFFFFF; + background-clip: content-box; border-radius: 8px; margin-left: -4px; margin-right: -4px; + display: flex; + flex-direction: row; + transform: 0.3s all; +} +.login-form__input-wrap--inactive { + opacity: 0.6; } .login-form__input-field::-webkit-input-placeholder { - color: rgba(41,77,115,0.2); + color: rgba(41,77,115,0.4); } .login-form__fields--invisible { @@ -89,16 +97,43 @@ width: 100%; border-radius: 8px; border: 0; - padding: 5px 16px; + padding: 10px 12px 12px 16px; font-family: DINPro; - font-size: 32px; - font-weight: bold; - line-height: 40px; + font-size: 20px; + font-weight: 900; + line-height: 26px; letter-spacing: 1px; color: #294D73; - background-color: #FFFFFF; + background-color: transparent; + flex: 1 1 auto; + transition: 0.3s all; +} + +.login-form__input-field--inactive { + background-color: rgba(255,255,255,0.6); } .login-form__input-field--error { color: #D0021B; -}
\ No newline at end of file +} + +.login-form__submit { + flex: 0 0 auto; + border: 0; + width: 48px; + background-color: transparent; + background-image: url(../assets/images/icon-arrow-inactive.svg); + background-position: center; + background-repeat: no-repeat; + transition: 0.3s all; +} + +.login-form__submit--active { + background-color: rgba(41,77,115,0.2); + background-image: url(../assets/images/icon-arrow-active.svg); +} + +.login-form__submit--invisible { + visibility: hidden; + opacity: 0; +} diff --git a/app/components/Login.js b/app/components/Login.js index 47a127c128..062510be00 100644 --- a/app/components/Login.js +++ b/app/components/Login.js @@ -83,6 +83,51 @@ export default class Login extends Component { } } + inputWrapClass(user) { + const classes = ['login-form__input-wrap']; + + if(user.status === LoginState.connecting) { + classes.push('login-form__input-wrap--inactive'); + } + + return classes.join(' '); + } + + inputClass(user) { + const map = { + [LoginState.failed]: 'login-form__input-field--error' + }; + const classes = ['login-form__input-field']; + const extra = map[user.status]; + + return classes.concat(extra ? extra : []).join(' '); + } + + footerClass(user) { + const map = { + [LoginState.ok]: 'login-footer--invisible', + [LoginState.connecting]: 'login-footer--invisible' + }; + const classes = ['login-footer']; + const extra = map[user.status]; + + return classes.concat(extra ? extra : []).join(' '); + } + + submitClass(user) { + const classes = ['login-form__submit']; + + if(user.account.length > 0) { + classes.push('login-form__submit--active'); + } + + if(user.status === LoginState.connecting) { + classes.push('login-form__submit--invisible'); + } + + return classes.join(' '); + } + render() { const { account, status, error } = this.props.user; const title = this.formTitle(status); @@ -91,9 +136,12 @@ export default class Login extends Component { const isConnecting = status === LoginState.connecting; const isFailed = status === LoginState.failed; const isLoggedIn = status === LoginState.ok; - const inputClass = ['login-form__input-field', isFailed ? 'login-form__input-field--error' : ''].join(' '); - const footerClass = ['login-footer', (isConnecting || isLoggedIn) ? 'login-footer--invisible' : ''].join(' '); - + + const inputWrapClass = this.inputWrapClass(this.props.user); + const inputClass = this.inputClass(this.props.user); + const footerClass = this.footerClass(this.props.user); + const submitClass = this.submitClass(this.props.user); + const autoFocusRef = input => { if(isFailed && input) { input.focus(); @@ -136,16 +184,17 @@ export default class Login extends Component { <div className="login-form__title">{ title }</div> <div className={ 'login-form__fields' + (isLoggedIn ? ' login-form__fields--invisible' : '') }> <div className="login-form__subtitle">{ subtitle }</div> - <div className="login-form__input-wrap"> + <div className={ inputWrapClass }> <input className={ inputClass } type="text" - placeholder="0000 0000 0000" + placeholder="e.g 0000 0000 0000" onChange={ ::this.handleInputChange } onKeyUp={ ::this.handleInputKeyUp } value={ displayAccount } disabled={ isConnecting } autoFocus={ true } ref={ autoFocusRef } /> + <button className={ submitClass } onClick={ ::this.handleLogin }></button> </div> </div> |
