Migrate subscription related pages to Bootstrap 5 (#26372)

* Enable Bootstrap 5 for the subscription error pages

* Override contact modal on the plans page

* Convert AI Assist related styles to CSS

* Extend single layout-website-redesign.pug template for both Bootstrap 3 and 5

* Formatting to tab indentation

* Add the switcher for AI Assist

* Fix translations in heading

GitOrigin-RevId: 54ddc35602831f1ec1fa83c9f67a091eefda7a77
This commit is contained in:
Rebeka Dekany
2025-06-19 08:05:05 +00:00
committed by Copybot
parent cc7c01132b
commit 8423829714
10 changed files with 415 additions and 174 deletions
@@ -1,28 +0,0 @@
extends ./layout-base
include ./_mixins/formMessages
include ./_mixins/bootstrap_js
block entrypointVar
- entrypoint = 'marketing'
- isWebsiteRedesign = true
block body
if (typeof(suppressNavbar) == "undefined")
include layout/navbar-marketing-bootstrap-5
block content
if (typeof(suppressFooter) == "undefined")
if showThinFooter
include layout/thin-footer-bootstrap-5
else
include layout/fat-footer-website-redesign
if (typeof(suppressCookieBanner) == 'undefined')
include _cookie_banner
!= moduleIncludes("contactModal-marketing-bootstrap-5", locals)
block prepend foot-scripts
+bootstrap-js(5)
@@ -8,20 +8,32 @@ block entrypointVar
block body
if (typeof(suppressNavbar) == "undefined")
include layout/navbar-website-redesign
if bootstrapVersion === 5
include layout/navbar-marketing-bootstrap-5
else
include layout/navbar-website-redesign
block content
//- bootstrapVersion needed here, because plans.pug uses both BS version
//- If the `plans-page-bs5` split test has been completed, remove bootstrapVersion logic
if (typeof(suppressFooter) == "undefined")
if showThinFooter
include layout/thin-footer
if bootstrapVersion === 5
include layout/thin-footer-bootstrap-5
else
include layout/thin-footer
else
include layout/fat-footer-website-redesign
if (typeof(suppressCookieBanner) == 'undefined')
include _cookie_banner
!= moduleIncludes("contactModal-marketing", locals)
block contactModal
if bootstrapVersion === 5
!= moduleIncludes("contactModal-marketing-bootstrap-5", locals)
else
!= moduleIncludes("contactModal-marketing", locals)
block prepend foot-scripts
+bootstrap-js(bootstrapVersion)
@@ -81,6 +81,10 @@ include ../../_mixins/eyebrow
.row
.col-xs-12.plans-faq-support
span #{translate('still_have_questions')}
button(data-ol-open-contact-form-modal="general")
button(
data-ol-open-contact-form-modal="general"
data-bs-toggle=bootstrapVersion === 5 ? "modal" : undefined
data-bs-target=bootstrapVersion === 5 ? "#contactUsModal" : undefined
)
span(style="margin-right: 4px") #{translate('contact_support')}
i.icon-md.material-symbols.material-symbols-rounded.material-symbols-arrow-right(aria-hidden="true") arrow_right_alt
@@ -1,10 +1,11 @@
extends ../layout-website-redesign-bootstrap-5
extends ../layout-website-redesign
include ../_mixins/recaptcha
include ../_mixins/notification
block vars
- var suppressNavbar = true
- var suppressFooter = true
- isWebsiteRedesign = true
block content
- var showCaptcha = settings.recaptcha && settings.recaptcha.siteKey && !(settings.recaptcha.disabled && settings.recaptcha.disabled.passwordReset)
@@ -1,4 +1,8 @@
extends ../layout-website-redesign-bootstrap-5
extends ../layout-website-redesign
block vars
- bootstrap5PageStatus = 'enabled'
- isWebsiteRedesign = true
block content
main#main-content
+65 -62
View File
@@ -1,69 +1,72 @@
extends ../layout-website-redesign-bootstrap-5
extends ../layout-website-redesign
include ../_mixins/recaptcha
block vars
- isWebsiteRedesign = true
block content
- var email = reconfirm_email ? reconfirm_email : ""
- var showCaptcha = settings.recaptcha && settings.recaptcha.siteKey && !(settings.recaptcha.disabled && settings.recaptcha.disabled.passwordReset)
- var email = reconfirm_email ? reconfirm_email : ""
- var showCaptcha = settings.recaptcha && settings.recaptcha.siteKey && !(settings.recaptcha.disabled && settings.recaptcha.disabled.passwordReset)
if showCaptcha
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render=explicit")
div(
id="recaptcha"
class="g-recaptcha"
data-sitekey=settings.recaptcha.siteKey
data-size="invisible"
data-badge="inline"
)
if showCaptcha
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render=explicit")
div(
id="recaptcha"
class="g-recaptcha"
data-sitekey=settings.recaptcha.siteKey
data-size="invisible"
data-badge="inline"
)
main#main-content(data-ol-captcha-retry-trigger-area="")
.container.auth-aux-container(style="max-width: 420px;")
form(
data-ol-async-form
name="reconfirmAccountForm"
action="/user/reconfirm"
method="POST"
aria-label=translate('request_reconfirmation_email')
captcha=(showCaptcha ? '' : false)
captcha-action-name=(showCaptcha ? "passwordReset" : false)
)
h1.h5.mb-3 #{translate("reconfirm_account")}
p #{translate('reconfirm_explained')}
|
a(href=`mailto:${settings.adminEmail}`) #{settings.adminEmail}
| .
div(data-ol-not-sent)
+formMessagesNewStyle()
main#main-content(data-ol-captcha-retry-trigger-area="")
.container.auth-aux-container(style="max-width: 420px;")
form(
data-ol-async-form
name="reconfirmAccountForm"
action="/user/reconfirm"
method="POST"
aria-label=translate('request_reconfirmation_email')
captcha=(showCaptcha ? '' : false)
captcha-action-name=(showCaptcha ? "passwordReset" : false)
)
h1.h5.mb-3 #{translate("reconfirm_account")}
p #{translate('reconfirm_explained')}
|
a(href=`mailto:${settings.adminEmail}`) #{settings.adminEmail}
| .
div(data-ol-not-sent)
+formMessagesNewStyle()
input(type="hidden" name="_csrf" value=csrfToken)
.form-group.mb-3
label.form-label(for='email') #{translate("please_enter_email")}
input.form-control(
aria-label="email"
type='email'
name='email'
placeholder='email@example.com'
required
autofocus
value=email
)
.actions
button.btn.btn-primary.w-100(
style="white-space: normal;"
type='submit'
data-ol-disabled-inflight
aria-label=translate('request_password_reset_to_reconfirm')
)
span(data-ol-inflight="idle")
| #{translate('request_password_reset_to_reconfirm')}
span(hidden data-ol-inflight="pending")
| #{translate('request_password_reset_to_reconfirm')}…
div(hidden data-ol-sent)
div.alert.alert-success(
role="alert"
aria-live="polite"
)
span #{translate('password_reset_email_sent')}
input(type="hidden" name="_csrf" value=csrfToken)
.form-group.mb-3
label.form-label(for='email') #{translate("please_enter_email")}
input.form-control(
aria-label="email"
type='email'
name='email'
placeholder='email@example.com'
required
autofocus
value=email
)
.actions
button.btn.btn-primary.w-100(
style="white-space: normal;"
type='submit'
data-ol-disabled-inflight
aria-label=translate('request_password_reset_to_reconfirm')
)
span(data-ol-inflight="idle")
| #{translate('request_password_reset_to_reconfirm')}
span(hidden data-ol-inflight="pending")
| #{translate('request_password_reset_to_reconfirm')}…
div(hidden data-ol-sent)
div.alert.alert-success(
role="alert"
aria-live="polite"
)
span #{translate('password_reset_email_sent')}
if showCaptcha
+recaptchaConditions
if showCaptcha
+recaptchaConditions
+1 -1
View File
@@ -23,7 +23,7 @@ block content
.row
.col-sm-12.col-md-6.col-md-offset-3
.card
h1.card-header #{translate("reconfirm")} #{translate("Account")}
h1.card-header #{translate("reconfirm_account")}
p #{translate('reconfirm_explained')} 
a(href=`mailto:${settings.adminEmail}`) #{settings.adminEmail}
| .
+77 -76
View File
@@ -1,90 +1,91 @@
extends ../layout-website-redesign-bootstrap-5
extends ../layout-website-redesign
block vars
- var suppressNavbar = true
- var suppressFooter = true
- var suppressNavbar = true
- var suppressFooter = true
- isWebsiteRedesign = true
block content
main#main-content
a.auth-aux-logo(href="/")
img(src=buildImgPath("ol-brand/overleaf-o-dark.svg") alt=settings.appName)
.auth-aux-container
form(
data-ol-async-form
name="passwordResetForm"
action="/user/password/set"
method="POST"
data-ol-hide-on-error="token-expired"
)
div(
hidden
data-ol-sent
)
h1.h3.mb-3.mt-0 #{translate("password_updated")}
p.mb-4 #{translate("your_password_has_been_successfully_changed")}.
a.btn.btn-primary.w-100(href='/login') #{translate("log_in_now")}
main#main-content
a.auth-aux-logo(href="/")
img(src=buildImgPath("ol-brand/overleaf-o-dark.svg") alt=settings.appName)
.auth-aux-container
form(
data-ol-async-form
name="passwordResetForm"
action="/user/password/set"
method="POST"
data-ol-hide-on-error="token-expired"
)
div(
hidden
data-ol-sent
)
h1.h3.mb-3.mt-0 #{translate("password_updated")}
p.mb-4 #{translate("your_password_has_been_successfully_changed")}.
a.btn.btn-primary.w-100(href='/login') #{translate("log_in_now")}
div(data-ol-not-sent)
h1.h3.mb-3.mt-0 #{translate("reset_your_password")}
p(data-ol-hide-on-error-message="token-expired") #{translate("create_a_new_password_for_your_account")}.
+formMessagesNewStyle()
div(data-ol-not-sent)
h1.h3.mb-3.mt-0 #{translate("reset_your_password")}
p(data-ol-hide-on-error-message="token-expired") #{translate("create_a_new_password_for_your_account")}.
+formMessagesNewStyle()
+customFormMessageNewStyle('password-contains-email', 'danger')
| #{translate('invalid_password_contains_email')}.
| #{translate('use_a_different_password')}.
+customFormMessageNewStyle('password-contains-email', 'danger')
| #{translate('invalid_password_contains_email')}.
| #{translate('use_a_different_password')}.
+customFormMessageNewStyle('password-too-similar', 'danger')
| #{translate('invalid_password_too_similar')}.
| #{translate('use_a_different_password')}.
+customFormMessageNewStyle('password-too-similar', 'danger')
| #{translate('invalid_password_too_similar')}.
| #{translate('use_a_different_password')}.
+customFormMessageNewStyle('token-expired', 'danger')
| #{translate('password_reset_token_expired')}
br
a(href="/user/password/reset")
| #{translate('request_new_password_reset_email')}
+customFormMessageNewStyle('token-expired', 'danger')
| #{translate('password_reset_token_expired')}
br
a(href="/user/password/reset")
| #{translate('request_new_password_reset_email')}
input(type="hidden" name="_csrf" value=csrfToken)
input(type="text" hidden name="email" autocomplete="username" value=email)
input(type="hidden" name="_csrf" value=csrfToken)
input(type="text" hidden name="email" autocomplete="username" value=email)
.form-group.mb-3
label.form-label(for='passwordField', data-ol-hide-on-error-message="token-expired") #{translate("new_password")}
input.form-control.auth-aux-new-password#passwordField(
type='password'
name='password'
autocomplete="new-password"
autofocus
required
minlength=settings.passwordStrengthOptions.length.min
)
.form-group.mb-3
label.form-label(for='passwordField', data-ol-hide-on-error-message="token-expired") #{translate("new_password")}
input.form-control.auth-aux-new-password#passwordField(
type='password'
name='password'
autocomplete="new-password"
autofocus
required
minlength=settings.passwordStrengthOptions.length.min
)
+customValidationMessageNewStyle('invalid-password')
| #{translate('invalid_password')}.
+customValidationMessageNewStyle('invalid-password')
| #{translate('invalid_password')}.
+customValidationMessageNewStyle('password-must-be-different')
| #{translate('password_cant_be_the_same_as_current_one')}.
+customValidationMessageNewStyle('password-must-be-different')
| #{translate('password_cant_be_the_same_as_current_one')}.
+customValidationMessageNewStyle('password-must-be-strong')
| !{translate('password_was_detected_on_a_public_list_of_known_compromised_passwords', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com/passwords', rel: 'noopener noreferrer', target: '_blank'}}])}.
| #{translate('use_a_different_password')}.
+customValidationMessageNewStyle('password-must-be-strong')
| !{translate('password_was_detected_on_a_public_list_of_known_compromised_passwords', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com/passwords', rel: 'noopener noreferrer', target: '_blank'}}])}.
| #{translate('use_a_different_password')}.
input(
type="hidden"
name="passwordResetToken"
value=passwordResetToken
)
div(data-ol-hide-on-error-message="token-expired")
div #{translate('in_order_to_have_a_secure_account_make_sure_your_password')}
ul.mb-3.ps-4
li #{translate('is_longer_than_n_characters', {n: settings.passwordStrengthOptions.length.min})}
li #{translate('does_not_contain_or_significantly_match_your_email')}
li #{translate('is_not_used_on_any_other_website')}
.actions
button.btn.btn-primary.w-100(
type='submit'
data-ol-disabled-inflight
aria-label=translate('set_new_password')
)
span(data-ol-inflight="idle")
| #{translate('set_new_password')}
span(hidden data-ol-inflight="pending")
| #{translate('set_new_password')}…
input(
type="hidden"
name="passwordResetToken"
value=passwordResetToken
)
div(data-ol-hide-on-error-message="token-expired")
div #{translate('in_order_to_have_a_secure_account_make_sure_your_password')}
ul.mb-3.ps-4
li #{translate('is_longer_than_n_characters', {n: settings.passwordStrengthOptions.length.min})}
li #{translate('does_not_contain_or_significantly_match_your_email')}
li #{translate('is_not_used_on_any_other_website')}
.actions
button.btn.btn-primary.w-100(
type='submit'
data-ol-disabled-inflight
aria-label=translate('set_new_password')
)
span(data-ol-inflight="idle")
| #{translate('set_new_password')}
span(hidden data-ol-inflight="pending")
| #{translate('set_new_password')}…
@@ -767,6 +767,247 @@ $z-index-group-member-picker-list: 1;
border-left: var(--border-width-base) solid var(--green-50);
}
.ai-assist {
color: var(--neutral-90);
@include media-breakpoint-up(lg) {
padding-left: 0 !important;
padding-right: 0 !important;
}
.ai-assist-heading {
margin-top: var(--spacing-12);
margin-bottom: var(--spacing-12);
text-align: center;
}
.ai-assist-container {
padding: var(--spacing-10);
border: var(--spacing-02) solid var(--neutral-10);
border-radius: var(--border-radius-large-new);
background:
linear-gradient(270deg, var(--blue-10), #fff) 0.13%,
#fff 63.21%;
@include media-breakpoint-down(lg) {
background: var(--bg-light-primary);
border-width: 2px;
border-radius: var(--border-radius-medium);
border-color: var(--premium-gradient);
padding: var(--spacing-09);
}
.ai-assist-content {
display: flex;
justify-content: space-between;
gap: var(--spacing-07);
@include media-breakpoint-down(lg) {
flex-direction: column;
}
.ai-assist-left {
display: flex;
gap: var(--spacing-07);
flex-direction: column;
max-width: 480px;
@include media-breakpoint-down(lg) {
max-width: 100%;
}
.ai-assist-price {
font-weight: 600;
font-size: var(--font-size-03);
@include media-breakpoint-down(lg) {
font-weight: normal;
font-size: var(--font-size-02);
.price {
font-size: var(--font-size-08);
font-weight: 600;
}
}
}
.ai-assist-annually-price {
display: block;
}
.ai-assist-monthly-price {
display: none;
}
.ai-assist-header-switch {
display: none;
}
.ai-assist-header {
display: flex;
align-items: center;
justify-content: space-between;
.ai-assist-header-content {
display: flex;
gap: var(--spacing-06);
align-items: center;
h3 {
font-size: var(--font-size-07);
margin: 0;
padding: 0;
@include media-breakpoint-down(lg) {
font-size: var(--font-size-05);
}
}
img {
@include media-breakpoint-down(lg) {
width: 24px;
}
}
}
.ai-assist-header-switch {
align-items: center;
gap: var(--spacing-03);
user-select: none;
input {
margin: 0;
}
label {
margin: 0;
font-weight: normal;
font-size: var(--font-size-03);
}
}
}
}
.ai-assist-right {
display: flex;
align-items: center;
gap: var(--spacing-06);
.ai-assist-features {
list-style: none;
display: flex;
flex-direction: column;
gap: var(--spacing-04);
min-width: 210px;
margin-bottom: 0;
.feature-item {
display: flex;
align-items: center;
font-size: var(--font-size-03);
cursor: default;
.feature-icon {
margin-right: var(--spacing-05);
color: var(--neutral-70);
width: 16px;
height: 16px;
}
.feature-text {
color: var(--neutral-90);
}
}
@include media-breakpoint-up(lg) {
.feature-item-selected {
.feature-text {
color: var(--blue-50);
font-weight: 600;
}
.feature-icon {
content: url(../../../../public/img/check-circle-blue-filled.svg);
}
}
}
}
.ai-assist-images {
display: flex;
align-items: flex-start;
width: 280px;
justify-content: center;
@include media-breakpoint-down(lg) {
display: none;
}
}
}
}
}
.ai-assist-header-switch {
display: flex !important;
}
.ai-assist-button-container {
display: flex;
gap: var(--spacing-05);
&.mobile {
display: none;
margin-top: var(--spacing-06);
flex-direction: column;
}
@include media-breakpoint-down(lg) {
&.mobile {
display: flex;
}
&.desktop {
display: none;
}
}
.btn.monthly {
display: none;
}
}
.overleaf-assist-screenshot {
height: auto;
max-width: 280px;
max-height: 200px;
border-radius: var(--border-radius-base-new);
display: none;
&.selected {
display: block;
animation: fade-in 1s;
}
}
}
.ai-assist.monthly-period {
.ai-assist-annually-price {
display: none !important;
}
.ai-assist-monthly-price {
display: block !important;
}
.ai-assist-button-container .btn.annual {
display: none !important;
}
.ai-assist-button-container .btn.monthly {
display: block !important;
}
}
.plans-new-organizations {
padding: var(--spacing-13) var(--spacing-08);
@@ -1,4 +1,7 @@
extends ../../../../../app/views/layout-website-redesign-bootstrap-5
extends ../../../../../app/views/layout-website-redesign
block vars
- isWebsiteRedesign = true
block content
main.content.content-alt#main-content