mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Merge pull request #25613 from overleaf/td-bs5-sp-login
Migrate SP/CE login page to Bootstrap 5 GitOrigin-RevId: 37fc7cbb453bfef93abde2080faaa0a88116d1f4
This commit is contained in:
@@ -4,11 +4,12 @@ mixin formMessages()
|
||||
role="alert"
|
||||
)
|
||||
|
||||
mixin formMessagesNewStyle()
|
||||
mixin formMessagesNewStyle(extraClass = 'form-messages-bottom-margin')
|
||||
- const attrs = extraClass ? { 'class': extraClass } : {}
|
||||
div(
|
||||
data-ol-form-messages-new-style='',
|
||||
role="alert"
|
||||
)
|
||||
)&attributes(attrs)
|
||||
|
||||
mixin customFormMessage(key, kind)
|
||||
if kind === 'success'
|
||||
@@ -36,20 +37,23 @@ mixin customFormMessage(key, kind)
|
||||
)
|
||||
block
|
||||
|
||||
mixin customFormMessageNewStyle(key, kind)
|
||||
mixin customFormMessageNewStyle(key, kind, extraClass = 'mb-3')
|
||||
- extraClass = extraClass ? ' ' + extraClass : ''
|
||||
if kind === 'success'
|
||||
div.notification.notification-type-success(
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
div(
|
||||
class="notification notification-type-success" + extraClass,
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
div.notification-icon
|
||||
span.material-symbols(aria-hidden="true") check_circle
|
||||
div.notification-content.text-left
|
||||
block
|
||||
else if kind === 'danger'
|
||||
div.notification.notification-type-error(
|
||||
div(
|
||||
class="notification notification-type-error" + extraClass,
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
@@ -60,12 +64,13 @@ mixin customFormMessageNewStyle(key, kind)
|
||||
div.notification-content.text-left
|
||||
block
|
||||
else
|
||||
div.notification.notification-type-warning(
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
div(
|
||||
class="notification notification-type-warning" + extraClass,
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
div.notification-icon
|
||||
span.material-symbols(aria-hidden="true") warning
|
||||
div.notification-content.text-left
|
||||
|
||||
@@ -1,52 +1,50 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-6.col-md-offset-3.col-lg-4.col-lg-offset-4
|
||||
.col-lg-6.offset-lg-3.col-xl-4.offset-xl-4
|
||||
.card
|
||||
.page-header
|
||||
if login_support_title
|
||||
h1 !{login_support_title}
|
||||
else
|
||||
h1 #{translate("log_in")}
|
||||
form(data-ol-async-form, name="loginForm", action='/login', method="POST")
|
||||
input(name='_csrf', type='hidden', value=csrfToken)
|
||||
+formMessages()
|
||||
+customFormMessage('invalid-password-retry-or-reset', 'danger')
|
||||
| !{translate('email_or_password_wrong_try_again_or_reset', {}, [{ name: 'a', attrs: { href: '/user/password/reset', 'aria-describedby': 'resetPasswordDescription' } }])}
|
||||
span.sr-only(id='resetPasswordDescription')
|
||||
| #{translate('reset_password_link')}
|
||||
+customValidationMessage('password-compromised')
|
||||
| !{translate('password_compromised_try_again_or_use_known_device_or_reset', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com/passwords', rel: 'noopener noreferrer', target: '_blank'}}, {name: 'a', attrs: {href: '/user/password/reset', target: '_blank'}}])}.
|
||||
.form-group
|
||||
input.form-control(
|
||||
type='email',
|
||||
name='email',
|
||||
required,
|
||||
placeholder='email@example.com',
|
||||
autofocus="true"
|
||||
)
|
||||
.form-group
|
||||
input.form-control(
|
||||
type='password',
|
||||
name='password',
|
||||
required,
|
||||
placeholder='********',
|
||||
)
|
||||
.actions
|
||||
button.btn-primary.btn(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight
|
||||
)
|
||||
span(data-ol-inflight="idle") #{translate("login")}
|
||||
span(hidden data-ol-inflight="pending") #{translate("logging_in")}…
|
||||
a.pull-right(href='/user/password/reset') #{translate("forgot_your_password")}?
|
||||
if login_support_text
|
||||
hr
|
||||
p.text-center !{login_support_text}
|
||||
|
||||
.card-body
|
||||
.page-header
|
||||
if login_support_title
|
||||
h1 !{login_support_title}
|
||||
else
|
||||
h1 #{translate("log_in")}
|
||||
form(data-ol-async-form, name="loginForm", action='/login', method="POST")
|
||||
input(name='_csrf', type='hidden', value=csrfToken)
|
||||
+formMessagesNewStyle()
|
||||
+customFormMessageNewStyle('invalid-password-retry-or-reset', 'danger')
|
||||
| !{translate('email_or_password_wrong_try_again_or_reset', {}, [{ name: 'a', attrs: { href: '/user/password/reset', 'aria-describedby': 'resetPasswordDescription' } }])}
|
||||
span.visually-hidden(id='resetPasswordDescription')
|
||||
| #{translate('reset_password_link')}
|
||||
+customFormMessageNewStyle('password-compromised')
|
||||
| !{translate('password_compromised_try_again_or_use_known_device_or_reset', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com/passwords', rel: 'noopener noreferrer', target: '_blank'}}, {name: 'a', attrs: {href: '/user/password/reset', target: '_blank'}}])}.
|
||||
.form-group
|
||||
input.form-control(
|
||||
type='email',
|
||||
name='email',
|
||||
required,
|
||||
placeholder='email@example.com',
|
||||
autofocus="true"
|
||||
)
|
||||
.form-group
|
||||
input.form-control(
|
||||
type='password',
|
||||
name='password',
|
||||
required,
|
||||
placeholder='********',
|
||||
)
|
||||
.actions
|
||||
button.btn-primary.btn(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight
|
||||
)
|
||||
span(data-ol-inflight="idle") #{translate("login")}
|
||||
span(hidden data-ol-inflight="pending") #{translate("logging_in")}…
|
||||
a.float-end(href='/user/password/reset') #{translate("forgot_your_password")}?
|
||||
if login_support_text
|
||||
hr
|
||||
p.text-center !{login_support_text}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export default function createIcon(type) {
|
||||
const icon = document.createElement('span')
|
||||
icon.className = 'material-symbols'
|
||||
icon.setAttribute('aria-hidden', 'true')
|
||||
icon.textContent = type
|
||||
return icon
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { canSkipCaptcha, validateCaptchaV2 } from './captcha'
|
||||
import inputValidator from './input-validator'
|
||||
import { disableElement, enableElement } from '../utils/disableElement'
|
||||
import { isBootstrap5 } from '@/features/utils/bootstrap-5'
|
||||
import createIcon from '@/features/form-helpers/create-icon'
|
||||
|
||||
// Form helper(s) to handle:
|
||||
// - Attaching to the relevant form elements
|
||||
@@ -164,10 +165,7 @@ function createNotificationFromMessageBS5(message) {
|
||||
if (materialIcon) {
|
||||
const iconEl = document.createElement('div')
|
||||
iconEl.className = 'notification-icon'
|
||||
const iconSpan = document.createElement('span')
|
||||
iconSpan.className = 'material-symbols'
|
||||
iconSpan.setAttribute('aria-hidden', 'true')
|
||||
iconSpan.textContent = materialIcon
|
||||
const iconSpan = createIcon(materialIcon)
|
||||
iconEl.append(iconSpan)
|
||||
messageEl.append(iconEl)
|
||||
}
|
||||
@@ -315,10 +313,9 @@ function showMessagesNewStyle(formEl, messageBag) {
|
||||
}
|
||||
|
||||
// create the left icon
|
||||
const icon = document.createElement('span')
|
||||
icon.className = 'material-symbols'
|
||||
icon.setAttribute('aria-hidden', 'true')
|
||||
icon.innerText = message.type === 'error' ? 'error' : 'check_circle'
|
||||
const icon = createIcon(
|
||||
message.type === 'error' ? 'error' : 'check_circle'
|
||||
)
|
||||
const messageIcon = document.createElement('div')
|
||||
messageIcon.className = 'notification-icon'
|
||||
messageIcon.appendChild(icon)
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
import { isBootstrap5 } from '@/features/utils/bootstrap-5'
|
||||
import createIcon from '@/features/form-helpers/create-icon'
|
||||
|
||||
export default function inputValidator(inputEl) {
|
||||
const messageEl = document.createElement('div')
|
||||
messageEl.className =
|
||||
inputEl.getAttribute('data-ol-validation-message-classes') ||
|
||||
'small text-danger mt-2'
|
||||
'small text-danger mt-2 form-text'
|
||||
messageEl.hidden = true
|
||||
|
||||
const messageInnerEl = messageEl.appendChild(document.createElement('span'))
|
||||
messageInnerEl.className = 'form-text-inner'
|
||||
|
||||
const messageTextNode = document.createTextNode('')
|
||||
|
||||
// In Bootstrap 5, add an icon
|
||||
if (isBootstrap5()) {
|
||||
const iconEl = createIcon('error')
|
||||
messageInnerEl.append(iconEl)
|
||||
}
|
||||
messageInnerEl.append(messageTextNode)
|
||||
|
||||
inputEl.insertAdjacentElement('afterend', messageEl)
|
||||
|
||||
// Hide messages until the user leaves the input field or submits the form.
|
||||
@@ -54,7 +70,7 @@ export default function inputValidator(inputEl) {
|
||||
// Require another blur before displaying errors again.
|
||||
canDisplayErrorMessages = false
|
||||
} else {
|
||||
messageEl.textContent = inputEl.validationMessage
|
||||
messageTextNode.data = inputEl.validationMessage
|
||||
messageEl.hidden = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,3 +257,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only apply bottom margin to form messages when it is non-empty
|
||||
.form-messages-bottom-margin > :last-child {
|
||||
margin-bottom: var(--spacing-06);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user