UX: More improvements to login/signup forms (#29417)
This commit is contained in:
parent
852ff18fb9
commit
81396467d0
|
@ -2,6 +2,7 @@
|
|||
<div id="credentials" class={{this.credentialsClass}}>
|
||||
<div class="input-group" {{did-insert this.passkeyConditionalLogin}}>
|
||||
<Input
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@value={{@loginName}}
|
||||
@type="email"
|
||||
id="login-account-name"
|
||||
|
@ -32,6 +33,7 @@
|
|||
</div>
|
||||
<div class="input-group">
|
||||
<PasswordField
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
{{on "keydown" this.loginOnEnter}}
|
||||
@value={{@loginPassword}}
|
||||
@capsLockOn={{this.capsLockOn}}
|
||||
|
@ -90,6 +92,7 @@
|
|||
<SecondFactorInput
|
||||
{{on "keydown" this.loginOnEnter}}
|
||||
{{on "input" (with-event-value (fn (mut @secondFactorToken)))}}
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@secondFactorMethod={{@secondFactorMethod}}
|
||||
value={{@secondFactorToken}}
|
||||
id="login-second-factor"
|
||||
|
|
|
@ -39,6 +39,14 @@ export default class LocalLoginForm extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
@action
|
||||
scrollInputIntoView(event) {
|
||||
event.target.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
togglePasswordMask() {
|
||||
this.maskPassword = !this.maskPassword;
|
||||
|
|
|
@ -20,7 +20,7 @@ const LoginPageCta = <template>
|
|||
{{/unless}}
|
||||
|
||||
{{#if @showSignupLink}}
|
||||
<span class="signup-page-cta__no-account-yet">
|
||||
<span class="login-page-cta__no-account-yet">
|
||||
{{i18n "create_account.no_account_yet"}}
|
||||
</span>
|
||||
<DButton
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
<div class="input-group create-account-email">
|
||||
<Input
|
||||
{{on "focusout" this.checkEmailAvailability}}
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@type="email"
|
||||
@value={{this.model.accountEmail}}
|
||||
disabled={{this.emailDisabled}}
|
||||
|
@ -54,7 +55,12 @@
|
|||
<label class="alt-placeholder" for="new-account-email">
|
||||
{{i18n "user.email.title"}}
|
||||
</label>
|
||||
{{#if this.emailValidation.reason}}
|
||||
{{#if
|
||||
(or
|
||||
this.emailValidation.ok
|
||||
(and this.emailValidationVisible this.emailValidation.reason)
|
||||
)
|
||||
}}
|
||||
<InputTip
|
||||
@validation={{this.emailValidation}}
|
||||
id="account-email-validation"
|
||||
|
@ -68,6 +74,7 @@
|
|||
|
||||
<div class="input-group create-account__username">
|
||||
<Input
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@value={{this.model.accountUsername}}
|
||||
disabled={{this.usernameDisabled}}
|
||||
maxlength={{this.maxUsernameLength}}
|
||||
|
@ -102,6 +109,8 @@
|
|||
<div class="input-group create-account__password">
|
||||
{{#if this.passwordRequired}}
|
||||
<PasswordField
|
||||
{{on "focusout" this.showPasswordValidation}}
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@value={{this.accountPassword}}
|
||||
@capsLockOn={{this.capsLockOn}}
|
||||
type={{if this.maskPassword "password" "text"}}
|
||||
|
@ -117,10 +126,20 @@
|
|||
|
||||
<div class="create-account__password-info">
|
||||
<div class="create-account__password-tip-validation">
|
||||
<InputTip
|
||||
@validation={{this.passwordValidation}}
|
||||
id="password-validation"
|
||||
/>
|
||||
{{#if
|
||||
(or
|
||||
this.passwordValidation.ok
|
||||
(and
|
||||
this.passwordValidationVisible
|
||||
this.passwordValidation.reason
|
||||
)
|
||||
)
|
||||
}}
|
||||
<InputTip
|
||||
@validation={{this.passwordValidation}}
|
||||
id="password-validation"
|
||||
/>
|
||||
{{/if}}
|
||||
<div
|
||||
class={{concat-class
|
||||
"caps-lock-warning"
|
||||
|
@ -157,6 +176,7 @@
|
|||
{{#if this.requireInviteCode}}
|
||||
<div class="input-group create-account__invite-code">
|
||||
<Input
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@value={{this.inviteCode}}
|
||||
id="inviteCode"
|
||||
class={{value-entered this.inviteCode}}
|
||||
|
@ -189,6 +209,7 @@
|
|||
>
|
||||
{{#if this.fullnameRequired}}
|
||||
<TextField
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@disabled={{this.nameDisabled}}
|
||||
@value={{this.model.accountName}}
|
||||
@id="new-account-name"
|
||||
|
@ -212,6 +233,7 @@
|
|||
{{#each this.userFields as |f|}}
|
||||
<div class="input-group">
|
||||
<UserField
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@field={{f.field}}
|
||||
@value={{f.value}}
|
||||
@validation={{f.validation}}
|
||||
|
|
|
@ -39,6 +39,8 @@ export default class CreateAccount extends Component.extend(
|
|||
userFields = null;
|
||||
isDeveloper = false;
|
||||
maskPassword = true;
|
||||
passwordValidationVisible = false;
|
||||
emailValidationVisible = false;
|
||||
|
||||
@notEmpty("model.authOptions") hasAuthOptions;
|
||||
@setting("enable_local_logins") canCreateLocal;
|
||||
|
@ -215,8 +217,18 @@ export default class CreateAccount extends Component.extend(
|
|||
});
|
||||
}
|
||||
|
||||
@action
|
||||
showPasswordValidation() {
|
||||
this.set(
|
||||
"passwordValidationVisible",
|
||||
Boolean(this.passwordValidation.reason)
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
checkEmailAvailability() {
|
||||
this.set("emailValidationVisible", Boolean(this.emailValidation.reason));
|
||||
|
||||
if (
|
||||
!this.emailValidation.ok ||
|
||||
this.serverAccountEmail === this.model.accountEmail
|
||||
|
@ -438,6 +450,14 @@ export default class CreateAccount extends Component.extend(
|
|||
});
|
||||
}
|
||||
|
||||
@action
|
||||
scrollInputIntoView(event) {
|
||||
event.target.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
togglePasswordMask() {
|
||||
this.toggleProperty("maskPassword");
|
||||
|
@ -453,6 +473,8 @@ export default class CreateAccount extends Component.extend(
|
|||
createAccount() {
|
||||
this.set("flash", "");
|
||||
this.set("forceValidationReason", true);
|
||||
this.set("emailValidationVisible", true);
|
||||
this.set("passwordValidationVisible", true);
|
||||
|
||||
const validation = [
|
||||
this.emailValidation,
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class LoginPageController extends Controller {
|
|||
@tracked loggingIn = false;
|
||||
@tracked loggedIn = false;
|
||||
@tracked showLoginButtons = true;
|
||||
@tracked showLogin = false;
|
||||
@tracked showLogin = true;
|
||||
@tracked showSecondFactor = false;
|
||||
@tracked loginPassword = "";
|
||||
@tracked loginName = "";
|
||||
|
|
|
@ -39,6 +39,8 @@ export default class SignupPageController extends Controller.extend(
|
|||
userFields = null;
|
||||
isDeveloper = false;
|
||||
maskPassword = true;
|
||||
passwordValidationVisible = false;
|
||||
emailValidationVisible = false;
|
||||
|
||||
@notEmpty("authOptions") hasAuthOptions;
|
||||
@setting("enable_local_logins") canCreateLocal;
|
||||
|
@ -204,8 +206,23 @@ export default class SignupPageController extends Controller.extend(
|
|||
});
|
||||
}
|
||||
|
||||
@action
|
||||
showPasswordValidation() {
|
||||
if (this.passwordValidation.reason) {
|
||||
this.set("passwordValidationVisible", true);
|
||||
} else {
|
||||
this.set("passwordValidationVisible", false);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
checkEmailAvailability() {
|
||||
if (this.emailValidation.reason) {
|
||||
this.set("emailValidationVisible", true);
|
||||
} else {
|
||||
this.set("emailValidationVisible", false);
|
||||
}
|
||||
|
||||
if (
|
||||
!this.emailValidation.ok ||
|
||||
this.serverAccountEmail === this.accountEmail
|
||||
|
@ -423,6 +440,14 @@ export default class SignupPageController extends Controller.extend(
|
|||
});
|
||||
}
|
||||
|
||||
@action
|
||||
scrollInputIntoView(event) {
|
||||
event.target.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
togglePasswordMask() {
|
||||
this.toggleProperty("maskPassword");
|
||||
|
@ -438,6 +463,8 @@ export default class SignupPageController extends Controller.extend(
|
|||
createAccount() {
|
||||
this.set("flash", "");
|
||||
this.set("forceValidationReason", true);
|
||||
this.set("emailValidationVisible", true);
|
||||
this.set("passwordValidationVisible", true);
|
||||
|
||||
const validation = [
|
||||
this.emailValidation,
|
||||
|
|
|
@ -300,6 +300,9 @@ export default class ApplicationRoute extends DiscourseRoute {
|
|||
} else if (this.siteSettings.experimental_full_page_login) {
|
||||
this.router.transitionTo("login").then((login) => {
|
||||
login.controller.set("canSignUp", this.controller.canSignUp);
|
||||
if (this.siteSettings.login_required) {
|
||||
login.controller.set("showLogin", true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.modal.show(LoginModal, {
|
||||
|
|
|
@ -21,7 +21,9 @@ export default class LoginRoute extends DiscourseRoute {
|
|||
}
|
||||
|
||||
model() {
|
||||
return StaticPage.find("login");
|
||||
if (this.siteSettings.login_required) {
|
||||
return StaticPage.find("login");
|
||||
}
|
||||
}
|
||||
|
||||
setupController(controller) {
|
||||
|
@ -31,5 +33,9 @@ export default class LoginRoute extends DiscourseRoute {
|
|||
controller.set("canSignUp", canSignUp);
|
||||
controller.set("flashType", "");
|
||||
controller.set("flash", "");
|
||||
|
||||
if (this.siteSettings.login_required) {
|
||||
controller.set("showLogin", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ export default RouteTemplate(
|
|||
} else if (response.needs_approval) {
|
||||
this.needsApproval = true;
|
||||
} else {
|
||||
setTimeout(this.loadHomepage, 2000);
|
||||
setTimeout(this.loadHomepage, 3000);
|
||||
}
|
||||
} catch (error) {
|
||||
this.errorMessage = i18n("user.activate_account.already_done");
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
{{hide-application-header-buttons "search" "login" "signup" "menu"}}
|
||||
{{hide-application-sidebar}}
|
||||
|
||||
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
||||
<div class="login-fullpage">
|
||||
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
||||
|
||||
<div class={{concat-class "login-body" this.bodyClasses}}>
|
||||
<PluginOutlet @name="login-before-modal-body" @connectorTagName="div" />
|
||||
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
{{hide-application-header-buttons "search" "login" "signup" "menu"}}
|
||||
{{hide-application-sidebar}}
|
||||
|
||||
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
||||
|
||||
<div class="signup-fullpage">
|
||||
<FlashMessage @flash={{this.flash}} @type={{this.flashType}} />
|
||||
|
||||
<div class={{concat-class "signup-body" this.bodyClasses}}>
|
||||
<PluginOutlet
|
||||
@name="create-account-before-modal-body"
|
||||
|
@ -37,6 +37,7 @@
|
|||
<div class="input-group create-account-email">
|
||||
<Input
|
||||
{{on "focusout" this.checkEmailAvailability}}
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@type="email"
|
||||
@value={{this.accountEmail}}
|
||||
disabled={{this.emailDisabled}}
|
||||
|
@ -50,7 +51,12 @@
|
|||
<label class="alt-placeholder" for="new-account-email">
|
||||
{{i18n "user.email.title"}}
|
||||
</label>
|
||||
{{#if this.emailValidation.reason}}
|
||||
{{#if
|
||||
(or
|
||||
this.emailValidation.ok
|
||||
(and this.emailValidationVisible this.emailValidation.reason)
|
||||
)
|
||||
}}
|
||||
<InputTip
|
||||
@validation={{this.emailValidation}}
|
||||
id="account-email-validation"
|
||||
|
@ -64,6 +70,7 @@
|
|||
|
||||
<div class="input-group create-account__username">
|
||||
<Input
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@value={{this.accountUsername}}
|
||||
disabled={{this.usernameDisabled}}
|
||||
maxlength={{this.maxUsernameLength}}
|
||||
|
@ -98,6 +105,8 @@
|
|||
<div class="input-group create-account__password">
|
||||
{{#if this.passwordRequired}}
|
||||
<PasswordField
|
||||
{{on "focusout" this.showPasswordValidation}}
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@value={{this.accountPassword}}
|
||||
@capsLockOn={{this.capsLockOn}}
|
||||
type={{if this.maskPassword "password" "text"}}
|
||||
|
@ -113,10 +122,20 @@
|
|||
|
||||
<div class="create-account__password-info">
|
||||
<div class="create-account__password-tip-validation">
|
||||
<InputTip
|
||||
@validation={{this.passwordValidation}}
|
||||
id="password-validation"
|
||||
/>
|
||||
{{#if
|
||||
(or
|
||||
this.passwordValidation.ok
|
||||
(and
|
||||
this.passwordValidationVisible
|
||||
this.passwordValidation.reason
|
||||
)
|
||||
)
|
||||
}}
|
||||
<InputTip
|
||||
@validation={{this.passwordValidation}}
|
||||
id="password-validation"
|
||||
/>
|
||||
{{/if}}
|
||||
<div
|
||||
class={{concat-class
|
||||
"caps-lock-warning"
|
||||
|
@ -153,6 +172,7 @@
|
|||
{{#if this.requireInviteCode}}
|
||||
<div class="input-group create-account__invite-code">
|
||||
<Input
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@value={{this.inviteCode}}
|
||||
id="inviteCode"
|
||||
class={{value-entered this.inviteCode}}
|
||||
|
@ -185,6 +205,7 @@
|
|||
>
|
||||
{{#if this.fullnameRequired}}
|
||||
<TextField
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@disabled={{this.nameDisabled}}
|
||||
@value={{this.accountName}}
|
||||
@id="new-account-name"
|
||||
|
@ -208,6 +229,7 @@
|
|||
{{#each this.userFields as |f|}}
|
||||
<div class="input-group">
|
||||
<UserField
|
||||
{{on "focusin" this.scrollInputIntoView}}
|
||||
@field={{f.field}}
|
||||
@value={{f.value}}
|
||||
@validation={{f.validation}}
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.above-main-container-outlet {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.activate-account-page .alert-error {
|
||||
|
@ -20,7 +23,6 @@
|
|||
max-width: 500px;
|
||||
padding: 2rem 3rem;
|
||||
background: var(--secondary);
|
||||
box-shadow: var(--shadow-menu-panel);
|
||||
margin: 10vh auto 1em auto;
|
||||
@media screen and (max-height: 700px) {
|
||||
margin: 1em auto 1em auto;
|
||||
|
|
|
@ -9,6 +9,17 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
#main-outlet:has(.login-fullpage, .signup-fullpage, .invites-show) {
|
||||
& ~ .powered-by-discourse,
|
||||
.above-main-container-outlet {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
body:has(.login-fullpage, .signup-fullpage) {
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
||||
.login-fullpage,
|
||||
.signup-fullpage,
|
||||
.invites-show {
|
||||
|
@ -18,6 +29,14 @@
|
|||
justify-content: center;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.alert {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login-page-cta,
|
||||
|
|
|
@ -217,11 +217,14 @@
|
|||
|
||||
/* end shared styles */
|
||||
|
||||
.d-modal.create-account {
|
||||
.d-modal.create-account,
|
||||
.d-modal.login-modal {
|
||||
&:not(:has(.login-right-side)) .d-modal__container {
|
||||
max-width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
.d-modal.create-account {
|
||||
.d-modal {
|
||||
&__container {
|
||||
width: 100%;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
max-width: 500px;
|
||||
padding: 2rem 3rem;
|
||||
background: var(--secondary);
|
||||
box-shadow: var(--shadow-menu-panel);
|
||||
margin: 10vh auto 1em auto;
|
||||
@media screen and (max-height: 700px) {
|
||||
margin: 1em auto 1em auto;
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
.login-fullpage,
|
||||
.signup-fullpage,
|
||||
.invites-show {
|
||||
&:not(:has(.has-alt-auth)) .alert {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.login-page-cta,
|
||||
.signup-page-cta {
|
||||
&__buttons {
|
||||
|
@ -71,3 +75,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invites-show.container {
|
||||
box-sizing: border-box;
|
||||
box-shadow: none;
|
||||
max-width: 550px;
|
||||
}
|
||||
|
|
|
@ -158,9 +158,12 @@
|
|||
}
|
||||
&__signup {
|
||||
background: none !important;
|
||||
font-size: var(--font-down);
|
||||
font-size: var(--font-up-1);
|
||||
padding: 0;
|
||||
}
|
||||
&__no-account-yet {
|
||||
font-size: var(--font-up-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,9 +179,12 @@
|
|||
}
|
||||
&__login {
|
||||
background: none !important;
|
||||
font-size: var(--font-down);
|
||||
font-size: var(--font-up-1);
|
||||
padding: 0;
|
||||
}
|
||||
&__existing-account {
|
||||
font-size: var(--font-up-1);
|
||||
}
|
||||
}
|
||||
|
||||
.login-right-side::before {
|
||||
|
|
Loading…
Reference in New Issue