Align subscription, login, restricted, and invite pages with website redesign (#31045)

* Replace the black Overleaf logo to the green one

* Move subscription, login, restricted, invite views to website-redesign layout

* Remove the Storybook showcase of all the layouts

---------

Co-authored-by: Antoine Clausse <antoine.clausse@overleaf.com>
GitOrigin-RevId: b07581834921750c9c6de44f05beb0dd9eafba23
This commit is contained in:
Rebeka Dekany
2026-01-29 09:06:03 +00:00
committed by Copybot
co-authored by Antoine Clausse
parent 77c66132b0
commit c4cdacc702
17 changed files with 121 additions and 328 deletions
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/add-seats'
@@ -21,5 +24,5 @@ block append meta
)
block content
main#main-content.content.content-alt
main#main-content.content
#add-seats-root
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/canceled-subscription'
@@ -7,4 +10,4 @@ block append meta
meta(name='ol-user' data-type='json' content=user)
block content
main#subscription-canceled-root.content.content-alt
main#subscription-canceled-root.content
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/dashboard'
@@ -91,5 +94,5 @@ block append meta
meta(name='ol-groupPlans' data-type='json' content=groupPlans)
block content
main#main-content.content.content-alt
main#main-content.content
#subscription-dashboard-root
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/manually-collected-subscription'
@@ -9,4 +12,4 @@ block append meta
meta(name='ol-errorType' data-type='string' content=errorType)
block content
main#manually-collected-subscription-root.content.content-alt
main#manually-collected-subscription-root.content
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/missing-billing-information'
@@ -8,4 +11,4 @@ block append meta
meta(name='ol-groupName' data-type='string' content=groupName)
block content
main#missing-billing-information-root.content.content-alt
main#missing-billing-information-root.content
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/preview-change'
@@ -23,5 +26,5 @@ block append meta
)
block content
main#main-content.content.content-alt
main#main-content.content
#subscription-preview-change
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/subtotal-limit-exceeded'
@@ -8,4 +11,4 @@ block append meta
meta(name='ol-groupName' data-type='string' content=groupName)
block content
main#subtotal-limit-exceeded-root.content.content-alt
main#subtotal-limit-exceeded-root.content
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/successful-subscription'
@@ -9,4 +12,4 @@ block append meta
meta(name='ol-user' data-type='json' content=user)
block content
main#subscription-success-root.content.content-alt
main#subscription-success-root.content
@@ -1,5 +1,8 @@
extends ../../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/group-invites'
@@ -8,4 +11,4 @@ block append meta
meta(name='ol-user' data-type='json' content=user)
block content
main#group-invites-root.content.content-alt.team-invite
main#group-invites-root.content.team-invite
@@ -1,5 +1,8 @@
extends ../../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/invite-managed'
@@ -20,4 +23,4 @@ block append meta
meta(name='ol-usersSubscription' data-type='json' content=usersSubscription)
block content
main#invite-managed-root.content.content-alt.team-invite
main#invite-managed-root.content.team-invite
@@ -1,5 +1,8 @@
extends ../../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/invite'
@@ -22,4 +25,4 @@ block append meta
meta(name='ol-user' data-type='json' content=user)
block content
main#invite-root.content.content-alt
main#invite-root.content
@@ -1,31 +1,32 @@
extends ../../layout-marketing
block vars
- isWebsiteRedesign = true
block append meta
meta(name='ol-user' data-type='json' content=user)
block content
main#main-content.content.content-alt.team-invite
main#main-content.content.team-invite
.container
.row
.col-lg-8.m-auto
.card.text-center
.card-body
.page-header
h1.text-center !{translate("invited_to_group", {inviterName: inviterName, appName: appName }, [{name: 'span', attrs: {class: 'team-invite-name'}}])}
.col-lg-8.m-auto.text-center
.page-header
h1 !{translate("invited_to_group", {inviterName: inviterName, appName: appName }, [{name: 'span', attrs: {class: 'team-invite-name'}}])}
if accountExists
div
p #{translate("invited_to_group_login_benefits", {appName: appName})}
p #{translate("invited_to_group_login", {emailAddress: emailAddress})}
p
a.btn.btn-primary(
href=`/login?redir=/subscription/invites/${inviteToken}${groupSSOActive ? "&hide_sso_login=true" : ""}`
) #{translate("login_to_accept_invitation")}
else
div
p #{translate("invited_to_group_register_benefits", {appName: appName})}
p #{translate("invited_to_group_register", {inviterName: inviterName})}
p
a.btn.btn-primary(
href=`/register?redir=/subscription/invites/${inviteToken}${groupSSOActive ? "&hide_sso_login=true" : ""}`
) #{translate("register_to_accept_invitation")}
if accountExists
div
p #{translate("invited_to_group_login_benefits", {appName: appName})}
p #{translate("invited_to_group_login", {emailAddress: emailAddress})}
p
a.btn.btn-primary(
href=`/login?redir=/subscription/invites/${inviteToken}${groupSSOActive ? "&hide_sso_login=true" : ""}`
) #{translate("login_to_accept_invitation")}
else
div
p #{translate("invited_to_group_register_benefits", {appName: appName})}
p #{translate("invited_to_group_register", {inviterName: inviterName})}
p
a.btn.btn-primary(
href=`/register?redir=/subscription/invites/${inviteToken}${groupSSOActive ? "&hide_sso_login=true" : ""}`
) #{translate("register_to_accept_invitation")}
@@ -1,5 +1,8 @@
extends ../layout-react
block vars
- isWebsiteRedesign = true
block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/upgrade-group-subscription'
@@ -19,4 +22,4 @@ block append meta
)
block content
main#upgrade-group-subscription-root.content.content-alt
main#upgrade-group-subscription-root.content
+44 -43
View File
@@ -1,48 +1,49 @@
extends ../layout-marketing
extends ../layout-website-redesign
block vars
- isWebsiteRedesign = true
block content
main#main-content.content.content-alt
main#main-content.content
.container
.row
.col-lg-6.offset-lg-3.col-xl-4.offset-xl-4
.card
.card-body
.page-header
if login_support_title
h1 !{login_support_title}
else
h1 #{translate("log_in")}
form(name='loginForm' data-ol-async-form 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
label(for='email') #{translate("email")}
input#email.form-control(
name='email'
type='email'
required
autofocus='true'
autocomplete='username'
)
.form-group
label(for='password') #{translate("password")}
input#password.form-control(
name='password'
type='password'
autocomplete='current-password'
required
)
.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}
.page-header
if login_support_title
h1 !{login_support_title}
else
h1 #{translate("log_in")}
form(name='loginForm' data-ol-async-form 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
label(for='email') #{translate("email")}
input#email.form-control(
name='email'
type='email'
required
autofocus='true'
autocomplete='username'
)
.form-group
label(for='password') #{translate("password")}
input#password.form-control(
name='password'
type='password'
autocomplete='current-password'
required
)
.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}
+4 -1
View File
@@ -1,6 +1,9 @@
extends ../layout-marketing
extends ../layout-website-redesign
include ../_mixins/material_symbol
block vars
- isWebsiteRedesign = true
block content
main.content#main-content
.container
@@ -14,7 +14,7 @@ import { useContactUsModal } from '@/shared/hooks/use-contact-us-modal'
import { UserProvider } from '@/shared/context/user-context'
import { X } from '@phosphor-icons/react'
import overleafWhiteLogo from '@/shared/svgs/overleaf-white.svg'
import overleafBlackLogo from '@/shared/svgs/overleaf-black.svg'
import overleafGreenLogo from '@/shared/svgs/overleaf-green.svg'
import type { CSSPropertiesWithVariables } from '../../../../../types/css-properties-with-variables'
function DefaultNavbar(
@@ -59,7 +59,7 @@ function DefaultNavbar(
style={
{
'--navbar-brand-image-default-url': `url("${overleafWhiteLogo}")`,
'--navbar-brand-image-redesign-url': `url("${overleafBlackLogo}")`,
'--navbar-brand-image-redesign-url': `url("${overleafGreenLogo}")`,
} as CSSPropertiesWithVariables
}
aria-label={t('primary')}
@@ -1,248 +0,0 @@
import _ from 'lodash'
import { ComponentType } from 'react'
import { Navbar } from 'react-bootstrap'
import OLPageContentCard from '@/shared/components/ol/ol-page-content-card'
import OLRow from '@/shared/components/ol/ol-row'
import OLCol from '@/shared/components/ol/ol-col'
import OLButton from '@/shared/components/ol/ol-button'
import CiamLayout from '@/shared/components/layouts/ciam-layout'
const lorem = (n: number) => {
const quacks = ['quack', 'quack', 'quack', 'quak']
let result = ''
if (n >= 1) result += 'Lorem'
if (n >= 2) result += ' epsom'
for (let i = 2; i < n; i++) {
const next =
result.at(-1) === '.'
? ' ' + _.capitalize(quacks[Math.floor(Math.random() * quacks.length)])
: quacks[Math.floor(Math.random() * (quacks.length + 1))]
result += next ? ' ' + next : '.'
}
if (result.at(-1) !== '.') result += '.'
return result
}
const Nav = () => <Navbar className="navbar-default navbar-main" />
export const UnsuportedBrowser = () => (
<main className="content content-alt full-height" id="main-content">
<div className="container full-height">
<div className="error-container full-height">
<div className="error-details">
<h1 className="error-status">Unsupported Browser</h1>
<p className="error-description">{lorem(60)}</p>
<hr />
<p>{lorem(40)}</p>
</div>
</div>
</div>
</main>
)
export const Error400 = () => (
<main className="content content-alt full-height" id="main-content">
<div className="container full-height">
<div className="error-container full-height">
<div className="error-details">
<p className="error-status">Something went wrong, sorry.</p>
<p className="error-description">{lorem(15)}</p>
</div>
</div>
</div>
</main>
)
export const Error404 = () => (
<>
<Nav />
<main className="content content-alt" id="main-content">
<div className="container">
<div className="error-container">
<div className="error-details">
<p className="error-status">Not found</p>
<p className="error-description">{lorem(20)}</p>
</div>
</div>
</div>
</main>
</>
)
export const Closed = () => (
<>
<Nav />
<main className="content" id="main-content">
<div className="container">
<div className="row">
<div className="col-lg-8 col-lg-offset-2 text-center">
<div className="page-header">
<h1>Maintenance</h1>
</div>
<p>{lorem(6)}</p>
</div>
</div>
</div>
</main>
</>
)
export const PlannedMaintenance = () => (
<>
<Nav />
<main className="content" id="main-content">
<div className="container">
<div className="row">
<div className="col-lg-8 col-lg-offset-2">
<div className="page-header">
<h1>Planned Maintenance</h1>
</div>
<p>{lorem(6)}</p>
</div>
</div>
</div>
</main>
</>
)
export const PostGateway = () => (
<>
<div className="content content-alt">
<div className="container">
<div className="row">
<div className="col-lg-6 offset-lg-3">
<div className="card">
<div className="card-body">
<p className="text-center">
Please wait while we process your request.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</>
)
export const Restricted = () => (
<>
<Nav />
<main className="content" id="main-content">
<div className="container">
<div className="row">
<div className="col-md-8 offset-md-2 text-center">
<div className="page-header">
<h2>
Restricted, sorry you don’t have permission to load this page.
</h2>
</div>
<p>{lorem(23)}</p>
</div>
</div>
</div>
</main>
</>
)
export const Invite = () => (
<main className="content content-alt" id="invite-root">
<OLRow className="row row-spaced">
<OLCol lg={{ span: 8, offset: 2 }}>
<OLPageContentCard>
<div className="page-header">
<h1 className="text-center">
<span className="team-invite-name">
max.mustermann@example.com
</span>{' '}
has invited you to join a group subscription on Overleaf
</h1>
</div>
<p className="text-center">{lorem(20)}</p>
</OLPageContentCard>
</OLCol>
</OLRow>
</main>
)
export const NotValid = () => (
<>
<Nav />
<main className="content content-alt" id="main-content">
<div className="container">
<div className="row">
<div className="col-md-8 col-md-offset-2 offset-md-2">
<div className="card project-invite-invalid">
<div className="card-body">
<div className="page-header text-center">
<h1>Invite not valid</h1>
</div>
<div className="row text-center">
<div className="col-12 col-md-12">
<p>{lorem(20)}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</>
)
export const CompleteRegistration = () => (
<>
<Nav />
<main className="content content-alt" id="main-content">
<div className="container">
<div className="row">
<div className="col-12 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2 offset-md-1 offset-lg-2">
<div className="card">
<div className="card-body">
<div className="page-header">
<h1 className="text-center">Dropbox Sync</h1>
</div>
<p>{lorem(20)}</p>
</div>
</div>
</div>
</div>
</div>
</main>
</>
)
export const Ciam = () => (
<CiamLayout>
<h1>Create your Overleaf account</h1>
<p>{lorem(20)}</p>
<hr />
<p>{lorem(20)}</p>
<OLButton>Button</OLButton>
</CiamLayout>
)
export default {
title: 'Shared / Layouts',
args: {
label: 'Option',
},
parameters: {
layout: 'fullscreen', // This is crucial for vh/vw layouts
},
decorators: [
(Story: ComponentType) => (
<div style={{ height: '100vh', width: '100vw' }}>
<style>
{`.content {
min-height: 100vh;
padding-top: 93px;
}`}
</style>
<Story />
</div>
),
],
}