Merge pull request 'Port of Refactor login page' (#4400) from 0ko/forgejo:ui-login-redesign into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4400
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
Earl Warren 2024-07-10 04:15:56 +00:00
commit 8acaa427d6
11 changed files with 177 additions and 161 deletions

View file

@ -4,7 +4,7 @@ dashboard = Dashboard
explore = Explore explore = Explore
help = Help help = Help
logo = Logo logo = Logo
sign_in = Sign In sign_in = Sign in
sign_in_with_provider = Sign in with %s sign_in_with_provider = Sign in with %s
sign_in_or = or sign_in_or = or
sign_out = Sign Out sign_out = Sign Out
@ -399,8 +399,6 @@ relevant_repositories = Only relevant repositories are being shown, <a href="%s"
[auth] [auth]
create_new_account = Register account create_new_account = Register account
register_helper_msg = Already have an account? Sign in now!
social_register_helper_msg = Already have an account? Link it now!
disable_register_prompt = Registration is disabled. Please contact your site administrator. disable_register_prompt = Registration is disabled. Please contact your site administrator.
disable_register_mail = Email confirmation for registration is disabled. disable_register_mail = Email confirmation for registration is disabled.
manual_activation_only = Contact your site administrator to complete activation. manual_activation_only = Contact your site administrator to complete activation.
@ -408,7 +406,9 @@ remember_me = Remember this device
remember_me.compromised = The login token is not valid anymore which may indicate a compromised account. Please check your account for unusual activities. remember_me.compromised = The login token is not valid anymore which may indicate a compromised account. Please check your account for unusual activities.
forgot_password_title= Forgot password forgot_password_title= Forgot password
forgot_password = Forgot password? forgot_password = Forgot password?
sign_up_now = Need an account? Register now. hint_login = Already have an account? <a href="%s">Sign in now!</a>
hint_register = Need an account? <a href="%s">Register now.</a>
sign_up_button = Register now.
sign_up_successful = Account was successfully created. Welcome! sign_up_successful = Account was successfully created. Welcome!
confirmation_mail_sent_prompt = A new confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the registration process. If the email is incorrect, you can log in, and request another confirmation email to be sent to a different address. confirmation_mail_sent_prompt = A new confirmation email has been sent to <b>%s</b>. Please check your inbox within the next %s to complete the registration process. If the email is incorrect, you can log in, and request another confirmation email to be sent to a different address.
must_change_password = Update your password must_change_password = Update your password
@ -440,10 +440,7 @@ use_scratch_code = Use a scratch code
twofa_scratch_used = You have used your scratch code. You have been redirected to the two-factor settings page so you may remove your device enrollment or generate a new scratch code. twofa_scratch_used = You have used your scratch code. You have been redirected to the two-factor settings page so you may remove your device enrollment or generate a new scratch code.
twofa_passcode_incorrect = Your passcode is incorrect. If you misplaced your device, use your scratch code to sign in. twofa_passcode_incorrect = Your passcode is incorrect. If you misplaced your device, use your scratch code to sign in.
twofa_scratch_token_incorrect = Your scratch code is incorrect. twofa_scratch_token_incorrect = Your scratch code is incorrect.
login_userpass = Sign In login_userpass = Sign in
tab_signin = Sign In
tab_signup = Sign Up
tab_openid = OpenID
oauth_signup_tab = Register new account oauth_signup_tab = Register new account
oauth_signup_title = Complete new account oauth_signup_title = Complete new account
oauth_signup_submit = Complete account oauth_signup_submit = Complete account
@ -473,6 +470,8 @@ sspi_auth_failed = SSPI authentication failed
password_pwned = The password you chose is on a <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">list of stolen passwords</a> previously exposed in public data breaches. Please try again with a different password and consider changing this password elsewhere too. password_pwned = The password you chose is on a <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">list of stolen passwords</a> previously exposed in public data breaches. Please try again with a different password and consider changing this password elsewhere too.
password_pwned_err = Could not complete request to HaveIBeenPwned password_pwned_err = Could not complete request to HaveIBeenPwned
last_admin = You cannot remove the last admin. There must be at least one admin. last_admin = You cannot remove the last admin. There must be at least one admin.
back_to_sign_in = Back to Sign in
sign_in_openid = Proceed with OpenID
[mail] [mail]
view_it_on = View it on %s view_it_on = View it on %s

View file

@ -1,5 +1,5 @@
{{if .EnableCaptcha}}{{if eq .CaptchaType "image"}} {{if .EnableCaptcha}}{{if eq .CaptchaType "image"}}
<div class="inline field"> <div class="inline field tw-text-center">
{{.Captcha.CreateHTML}} {{.Captcha.CreateHTML}}
</div> </div>
<div class="required field {{if .Err_Captcha}}error{{end}}"> <div class="required field {{if .Err_Captcha}}error{{end}}">
@ -7,18 +7,17 @@
<input id="captcha" name="captcha" value="{{.captcha}}" autocomplete="off"> <input id="captcha" name="captcha" value="{{.captcha}}" autocomplete="off">
</div> </div>
{{else if eq .CaptchaType "recaptcha"}} {{else if eq .CaptchaType "recaptcha"}}
<div class="inline field required"> <div class="inline field tw-text-center required">
<div id="captcha" data-captcha-type="g-recaptcha" class="g-recaptcha-style" data-sitekey="{{.RecaptchaSitekey}}"></div> <div id="captcha" data-captcha-type="g-recaptcha" class="g-recaptcha-style" data-sitekey="{{.RecaptchaSitekey}}"></div>
</div> </div>
<script src='{{URLJoin .RecaptchaURL "api.js"}}'></script> <script src='{{URLJoin .RecaptchaURL "api.js"}}'></script>
{{else if eq .CaptchaType "hcaptcha"}} {{else if eq .CaptchaType "hcaptcha"}}
<div class="inline field required"> <div class="inline field tw-text-center required">
<div id="captcha" data-captcha-type="h-captcha" class="h-captcha-style" data-sitekey="{{.HcaptchaSitekey}}"></div> <div id="captcha" data-captcha-type="h-captcha" class="h-captcha-style" data-sitekey="{{.HcaptchaSitekey}}"></div>
</div> </div>
<script src='https://hcaptcha.com/1/api.js'></script> <script src='https://hcaptcha.com/1/api.js'></script>
{{else if eq .CaptchaType "mcaptcha"}} {{else if eq .CaptchaType "mcaptcha"}}
<div class="inline field"> <div class="inline field tw-text-center">
<label></label>
<div class="m-captcha-style" id="mcaptcha__widget-container"></div> <div class="m-captcha-style" id="mcaptcha__widget-container"></div>
<div id="captcha" data-captcha-type="m-captcha" data-sitekey="{{.McaptchaSitekey}}" data-instance-url="{{.McaptchaURL}}"></div> <div id="captcha" data-captcha-type="m-captcha" data-sitekey="{{.McaptchaSitekey}}" data-instance-url="{{.McaptchaURL}}"></div>
</div> </div>

View file

@ -35,7 +35,7 @@
{{if .ShowRegistrationButton}} {{if .ShowRegistrationButton}}
<div class="inline field"> <div class="inline field">
<label></label> <label></label>
<a href="{{AppSubUrl}}/user/sign_up">{{ctx.Locale.Tr "auth.sign_up_now"}}</a> <a href="{{AppSubUrl}}/user/sign_up">{{ctx.Locale.Tr "auth.sign_up_button"}}</a>
</div> </div>
{{end}} {{end}}
</form> </form>

View file

@ -0,0 +1,29 @@
{{if or .OAuth2Providers .EnableOpenIDSignIn}}
<div class="divider divider-text">
{{ctx.Locale.Tr "sign_in_or"}}
</div>
<div id="oauth2-login-navigator" class="tw-py-1">
<div class="tw-flex tw-flex-col tw-justify-center">
<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">
{{range $provider := .OAuth2Providers}}
<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
{{$provider.IconHTML 28}}
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
</a>
{{end}}
{{if .EnableOpenIDSignIn}}
<a class="openid ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full" href="{{AppSubUrl}}/user/login/openid">
{{svg "fontawesome-openid" 28 "tw-mr-2"}}
{{ctx.Locale.Tr "auth.sign_in_openid"}}
</a>
{{end}}
{{if .EnableSSPI}}
<a class="ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full" rel="nofollow" href="{{AppSubUrl}}/user/login?auth_with_sspi=1">
{{svg "fontawesome-windows"}}
&nbsp;SSPI
</a>
{{end}}
</div>
</div>
</div>
{{end}}

View file

@ -1,8 +1,7 @@
{{template "base/head" .}} {{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content user signin{{if .LinkAccountMode}} icon{{end}}"> <div role="main" aria-label="{{.Title}}" class="page-content user signin{{if .LinkAccountMode}} icon{{end}}">
{{template "user/auth/signin_navbar" .}}
<div class="ui middle very relaxed page grid"> <div class="ui middle very relaxed page grid">
<div class="ui container column fluid"> <div class="column tw-flex tw-flex-col tw-gap-4 tw-max-w-2xl tw-m-auto">
{{template "user/auth/signin_inner" .}} {{template "user/auth/signin_inner" .}}
</div> </div>
</div> </div>

View file

@ -1,23 +1,25 @@
{{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn)}} <div class="ui container fluid">
{{template "base/alert" .}} {{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn)}}
{{end}} {{template "base/alert" .}}
<h4 class="ui top attached header center"> {{end}}
<h4 class="ui top attached header center">
{{if .LinkAccountMode}} {{if .LinkAccountMode}}
{{ctx.Locale.Tr "auth.oauth_signin_title"}} {{ctx.Locale.Tr "auth.oauth_signin_title"}}
{{else}} {{else}}
{{ctx.Locale.Tr "auth.login_userpass"}} {{ctx.Locale.Tr "auth.login_userpass"}}
{{end}} {{end}}
</h4> </h4>
<div class="ui attached segment"> <div class="ui attached segment">
<form class="ui form tw-max-w-2xl tw-m-auto" action="{{.SignInLink}}" method="post"> <form class="ui form" action="{{.SignInLink}}" method="post">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
<div class="required field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}"> <div class="required field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
<label for="user_name">{{ctx.Locale.Tr "home.uname_holder"}}</label> <label for="user_name">{{ctx.Locale.Tr "home.uname_holder"}}</label>
<input id="user_name" type="text" name="user_name" value="{{.user_name}}" autofocus required> <input id="user_name" type="text" name="user_name" value="{{.user_name}}" autofocus required>
</div> </div>
{{if or (not .DisablePassword) .LinkAccountMode}} {{if or (not .DisablePassword) .LinkAccountMode}}
<div class="required field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}"> <div class="required field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}} form-field-content-aside-label">
<label for="password">{{ctx.Locale.Tr "password"}}</label> <label for="password">{{ctx.Locale.Tr "password"}}</label>
<a href="{{AppSubUrl}}/user/forgot_password">{{ctx.Locale.Tr "auth.forgot_password"}}</a>
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="current-password" required> <input id="password" name="password" type="password" value="{{.password}}" autocomplete="current-password" required>
</div> </div>
{{end}} {{end}}
@ -33,38 +35,28 @@
{{template "user/auth/captcha" .}} {{template "user/auth/captcha" .}}
<div class="field"> <div class="field">
<button class="ui primary button"> <button class="ui primary button tw-w-full">
{{if .LinkAccountMode}} {{if .LinkAccountMode}}
{{ctx.Locale.Tr "auth.oauth_signin_submit"}} {{ctx.Locale.Tr "auth.oauth_signin_submit"}}
{{else}} {{else}}
{{ctx.Locale.Tr "sign_in"}} {{ctx.Locale.Tr "sign_in"}}
{{end}} {{end}}
</button> </button>
<a href="{{AppSubUrl}}/user/forgot_password">{{ctx.Locale.Tr "auth.forgot_password"}}</a>
</div> </div>
</form>
{{template "user/auth/oauth_container" .}}
</div>
</div>
<div class="ui container fluid">
{{template "user/auth/webauthn_error" .}}
<div class="ui attached segment header top tw-max-w-2xl tw-m-auto tw-flex tw-flex-col tw-items-center">
{{if .ShowRegistrationButton}} {{if .ShowRegistrationButton}}
<div class="field"> <div class="field">
<a href="{{AppSubUrl}}/user/sign_up">{{ctx.Locale.Tr "auth.sign_up_now"}}</a> {{ctx.Locale.Tr "auth.hint_register" (printf "%s/user/sign_up" AppSubUrl)}}
</div> </div>
{{end}} {{end}}
{{if .OAuth2Providers}}
<div class="divider divider-text">
{{ctx.Locale.Tr "sign_in_or"}}
</div> </div>
<div id="oauth2-login-navigator" class="tw-py-1">
<div class="tw-flex tw-flex-col tw-justify-center">
<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">
{{range $provider := .OAuth2Providers}}
<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
{{$provider.IconHTML 28}}
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
</a>
{{end}}
</div>
</div>
</div>
{{end}}
</form>
</div> </div>

View file

@ -1,24 +0,0 @@
{{if or .EnableOpenIDSignIn .EnableSSPI}}
<overflow-menu class="ui secondary pointing tabular top attached borderless menu navbar secondary-nav">
<div class="overflow-menu-items tw-justify-center">
<a class="{{if .PageIsLogin}}active {{end}}item" rel="nofollow" href="{{AppSubUrl}}/user/login">
{{ctx.Locale.Tr "auth.tab_signin"}}
</a>
<a class="{{if .PageIsSignUp}}active{{end}} item" rel="nofollow" href="{{AppSubUrl}}/user/sign_up">
{{ctx.Locale.Tr "auth.tab_signup"}}
</a>
{{if .EnableOpenIDSignIn}}
<a class="{{if .PageIsLoginOpenID}}active {{end}}item" rel="nofollow" href="{{AppSubUrl}}/user/login/openid">
{{svg "fontawesome-openid"}}
&nbsp;{{ctx.Locale.Tr "auth.tab_openid"}}
</a>
{{end}}
{{if .EnableSSPI}}
<a class="item" rel="nofollow" href="{{AppSubUrl}}/user/login?auth_with_sspi=1">
{{svg "fontawesome-windows"}}
&nbsp;SSPI
</a>
{{end}}
</div>
</overflow-menu>
{{end}}

View file

@ -1,7 +1,12 @@
{{template "base/head" .}} {{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content user signin openid"> <div role="main" aria-label="{{.Title}}" class="page-content user signin openid">
{{template "user/auth/signin_navbar" .}} <div class="ui middle very relaxed page grid">
<div class="ui container"> <div class="column tw-flex tw-flex-col tw-gap-4 tw-max-w-2xl tw-m-auto">
<a href="{{AppSubUrl}}/user/login" class="tw-mx-auto">
<img width="100" height="100" src="{{AssetUrlPrefix}}/img/logo.svg" alt="{{ctx.Locale.Tr "logo"}}">
</a>
<div class="ui container fluid">
{{template "base/alert" .}} {{template "base/alert" .}}
<h4 class="ui top attached header center"> <h4 class="ui top attached header center">
{{svg "fontawesome-openid"}} {{svg "fontawesome-openid"}}
@ -27,10 +32,20 @@
</div> </div>
</div> </div>
<div class="inline field"> <div class="inline field">
<button class="ui primary button">{{ctx.Locale.Tr "sign_in"}}</button> <button class="ui primary button tw-w-full">{{ctx.Locale.Tr "sign_in"}}</button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
<div class="ui container fluid">
{{template "user/auth/webauthn_error" .}}
<div class="ui attached segment header top tw-flex tw-flex-col tw-items-center">
<a href="{{AppSubUrl}}/user/login">{{ctx.Locale.Tr "auth.back_to_sign_in"}}</a>
</div>
</div>
</div>
</div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

View file

@ -1,8 +1,9 @@
{{template "base/head" .}} {{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content user signin{{if .LinkAccountMode}} icon{{end}}"> <div role="main" aria-label="{{.Title}}" class="page-content user signin{{if .LinkAccountMode}} icon{{end}}">
{{template "user/auth/signin_navbar" .}}
<div class="ui middle very relaxed page grid"> <div class="ui middle very relaxed page grid">
<div class="column tw-flex tw-flex-col tw-gap-4 tw-max-w-2xl tw-m-auto">
{{template "user/auth/signup_inner" .}} {{template "user/auth/signup_inner" .}}
</div> </div>
</div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

View file

@ -1,4 +1,4 @@
<div class="ui container column fluid{{if .LinkAccountMode}} icon{{end}}"> <div class="ui container fluid{{if .LinkAccountMode}} icon{{end}}">
<h4 class="ui top attached header center"> <h4 class="ui top attached header center">
{{if .LinkAccountMode}} {{if .LinkAccountMode}}
{{ctx.Locale.Tr "auth.oauth_signup_title"}} {{ctx.Locale.Tr "auth.oauth_signup_title"}}
@ -7,7 +7,7 @@
{{end}} {{end}}
</h4> </h4>
<div class="ui attached segment"> <div class="ui attached segment">
<form class="ui form tw-max-w-2xl tw-m-auto" action="{{.SignUpLink}}" method="post"> <form class="ui form" action="{{.SignUpLink}}" method="post">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
{{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister)}} {{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister)}}
{{template "base/alert" .}} {{template "base/alert" .}}
@ -38,7 +38,7 @@
{{template "user/auth/captcha" .}} {{template "user/auth/captcha" .}}
<div class="inline field"> <div class="inline field">
<button class="ui primary button"> <button class="ui primary button tw-w-full">
{{if .LinkAccountMode}} {{if .LinkAccountMode}}
{{ctx.Locale.Tr "auth.oauth_signup_submit"}} {{ctx.Locale.Tr "auth.oauth_signup_submit"}}
{{else}} {{else}}
@ -46,31 +46,19 @@
{{end}} {{end}}
</button> </button>
</div> </div>
{{if not .LinkAccountMode}}
<div class="inline field">
<a href="{{AppSubUrl}}/user/login">{{ctx.Locale.Tr "auth.register_helper_msg"}}</a>
</div>
{{end}}
{{end}} {{end}}
{{if .OAuth2Providers}} {{template "user/auth/oauth_container" .}}
<div class="divider divider-text">
{{ctx.Locale.Tr "sign_in_or"}}
</div>
<div id="oauth2-login-navigator" class="tw-py-1">
<div class="tw-flex tw-flex-col tw-justify-center">
<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">
{{range $provider := .OAuth2Providers}}
<a class="{{$provider.Name}} ui button tw-flex tw-items-center tw-justify-center tw-py-2 tw-w-full oauth-login-link" href="{{AppSubUrl}}/user/oauth2/{{$provider.DisplayName}}">
{{$provider.IconHTML 28}}
{{ctx.Locale.Tr "sign_in_with_provider" $provider.DisplayName}}
</a>
{{end}}
</div>
</div>
</div>
{{end}}
</form> </form>
</div> </div>
</div> </div>
<div class="ui container fluid">
<div class="ui attached segment header top tw-flex tw-flex-col tw-items-center">
{{if not .LinkAccountMode}}
<div class="field">
{{ctx.Locale.Tr "auth.hint_login" (printf "%s/user/login" AppSubUrl)}}
</div>
{{end}}
</div>
</div>

View file

@ -448,6 +448,24 @@ textarea:focus,
} }
} }
/* form fields with additional content besides their label, used on login form
* use like <div class="field"><label/><a/><input/></div> */
.form-field-content-aside-label {
display: grid;
grid-template-columns: 1fr 1fr;
}
.form-field-content-aside-label > *:nth-child(2) {
text-align: right;
margin-bottom: 4px;
}
.form-field-content-aside-label input {
grid-column: span 2;
}
.ui.form .field > .selection.dropdown {
min-width: 14em; /* matches the default min width */
}
.new.webhook form .help { .new.webhook form .help {
margin-left: 25px; margin-left: 25px;
} }