From 33fa5986c8214a86f9198c803c034fd4c554e92b Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 18 Jun 2026 12:56:34 +0000 Subject: [PATCH] Email rebranding, mobile filter alignment fix, minor UI cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Email: - Replace Overleaf green palette with Verso teal (#2a9d8f) for CTA buttons, links, and logo text - Rename force-overleaf-style CSS class to force-verso-style in all email body templates and layout - Replace all user-visible "Overleaf" strings with settings.appName across email subjects, bodies, and sign-offs (EmailBuilder.mjs) - Remove Overleaf CEO signature from onboarding email; substitute "The Verso Team" - Fix utm_source=overleaf → utm_source=verso in onboarding links - Point git token docs URL to local siteUrl instead of docs.overleaf.com - Fix hard-coded Overleaf green (#0F7A06) in SSO disabled email link Mobile filter chips: - Switch from overflow-x:auto (still leaks through ancestor flex chain) to flex-wrap:wrap with flex:1 1 auto on each chip so all chips in a row grow to equal width — no overflow, clean alignment - Toolbar becomes flex-column: chips on top, zoom below-right Misc: - Remove import_typst_file option from new-project menu - Add interface_language to extracted-translations.json whitelist Co-Authored-By: Claude Sonnet 4.6 --- .../Features/Email/Bodies/NoCTAEmailBody.mjs | 4 +- .../Email/Bodies/UpdatedNoCTAEmailBody.mjs | 2 +- .../src/Features/Email/Bodies/cta-email.mjs | 10 +-- .../Email/Bodies/updated-cta-email.mjs | 4 +- .../app/src/Features/Email/EmailBuilder.mjs | 77 ++++++++----------- .../Email/Layouts/UpdatedBaseEmailLayout.mjs | 14 ++-- .../app/src/Features/Email/emailStyles.mjs | 8 +- .../web/frontend/extracted-translations.json | 1 + .../components/new-project-button.tsx | 18 +---- .../pages/project-list-lumiere.scss | 61 +++++++-------- 10 files changed, 81 insertions(+), 118 deletions(-) diff --git a/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.mjs b/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.mjs index a078cad8e6..28f990ae03 100644 --- a/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.mjs +++ b/services/web/app/src/Features/Email/Bodies/NoCTAEmailBody.mjs @@ -9,7 +9,7 @@ export default _.template(`\ <% if (title) { %> -

+

<%= title %>

<% } %> @@ -25,7 +25,7 @@ export default _.template(`\ <% } %> <% (message).forEach(function(paragraph) { %> -

+

<%= paragraph %>

<% }) %> diff --git a/services/web/app/src/Features/Email/Bodies/UpdatedNoCTAEmailBody.mjs b/services/web/app/src/Features/Email/Bodies/UpdatedNoCTAEmailBody.mjs index 6a314c2926..a2d2d5ad7f 100644 --- a/services/web/app/src/Features/Email/Bodies/UpdatedNoCTAEmailBody.mjs +++ b/services/web/app/src/Features/Email/Bodies/UpdatedNoCTAEmailBody.mjs @@ -15,7 +15,7 @@ export default _.template(`\ <% } %> <% (message).forEach(function(paragraph) { %> -

+

<%= paragraph %>

<% }) %> diff --git a/services/web/app/src/Features/Email/Bodies/cta-email.mjs b/services/web/app/src/Features/Email/Bodies/cta-email.mjs index 6d49620a7d..b42091ddc2 100644 --- a/services/web/app/src/Features/Email/Bodies/cta-email.mjs +++ b/services/web/app/src/Features/Email/Bodies/cta-email.mjs @@ -9,7 +9,7 @@ export default _.template(`\ <% if (title) { %> -

+

<%= title %>

<% } %> @@ -25,7 +25,7 @@ export default _.template(`\ <% } %> <% (message).forEach(function(paragraph) { %> -

+

<%= paragraph %>

<% }) %> @@ -52,7 +52,7 @@ export default _.template(`\

 

<% (secondaryMessage).forEach(function(paragraph) { %> -

+

<%= paragraph %>

<% }) %> @@ -60,11 +60,11 @@ export default _.template(`\

 

-

+

If the button above does not appear, please copy and paste this link into your browser's address bar:

-

+

<%= ctaURL %>

diff --git a/services/web/app/src/Features/Email/Bodies/updated-cta-email.mjs b/services/web/app/src/Features/Email/Bodies/updated-cta-email.mjs index 8987b62251..150536fd90 100644 --- a/services/web/app/src/Features/Email/Bodies/updated-cta-email.mjs +++ b/services/web/app/src/Features/Email/Bodies/updated-cta-email.mjs @@ -15,7 +15,7 @@ export default _.template(`\ <% } %> <% (message).forEach(function(paragraph) { %> -

+

<%= paragraph %>

<% }) %> @@ -32,7 +32,7 @@ export default _.template(`\ <% if (secondaryMessage && secondaryMessage.length > 0) { %> <% (secondaryMessage).forEach(function(paragraph) { %> -

+

<%= paragraph %>

<% }) %> diff --git a/services/web/app/src/Features/Email/EmailBuilder.mjs b/services/web/app/src/Features/Email/EmailBuilder.mjs index 69bb1f3adb..07e7e66e72 100644 --- a/services/web/app/src/Features/Email/EmailBuilder.mjs +++ b/services/web/app/src/Features/Email/EmailBuilder.mjs @@ -276,7 +276,7 @@ templates.confirmCode = NoCTAEmailTemplate({ return '' }, subject(opts) { - return `Confirm your email address on Overleaf (${opts.confirmCode})` + return `Confirm your email address on ${settings.appName} (${opts.confirmCode})` }, title(opts) { return 'Confirm your email address' @@ -284,7 +284,7 @@ templates.confirmCode = NoCTAEmailTemplate({ message(opts, isPlainText) { const msg = opts.welcomeUser ? [ - `Welcome to Overleaf! We're so glad you joined us.`, + `Welcome to ${settings.appName}! We're so glad you joined us.`, 'Use this 6-digit confirmation code to finish your setup.', ] : ['Use this 6-digit code to confirm your email address.'] @@ -477,7 +477,7 @@ templates.inviteNewUserToJoinManagedUsers = ctaTemplate({ templates.groupSSOLinkingInvite = ctaTemplate({ subject(opts) { const subjectPrefix = opts.reminder ? 'Reminder: ' : 'Action required: ' - return `${subjectPrefix}Authenticate your Overleaf account` + return `${subjectPrefix}Authenticate your ${settings.appName} account` }, title(opts) { const titlePrefix = opts.reminder ? 'Reminder: ' : '' @@ -495,8 +495,8 @@ templates.groupSSOLinkingInvite = ctaTemplate({
- You won't need to remember a separate email address and password to sign in to Overleaf. - All you need to do is authenticate your existing Overleaf account with your SSO provider. + You won't need to remember a separate email address and password to sign in to ${settings.appName}. + All you need to do is authenticate your existing ${settings.appName} account with your SSO provider.
`, ] @@ -517,7 +517,7 @@ templates.groupSSOLinkingInvite = ctaTemplate({ templates.groupSSOReauthenticate = ctaTemplate({ subject(opts) { - return 'Action required: Reauthenticate your Overleaf account' + return \`Action required: Reauthenticate your \${settings.appName} account\` }, title(opts) { return 'Action required: Reauthenticate SSO' @@ -526,8 +526,8 @@ templates.groupSSOReauthenticate = ctaTemplate({ return [ `Hi,
- Single sign-on for your Overleaf group has been updated. - This means you need to reauthenticate your Overleaf account with your group’s SSO provider. + Single sign-on for your ${settings.appName} group has been updated. + This means you need to reauthenticate your ${settings.appName} account with your group’s SSO provider.
`, ] @@ -538,7 +538,7 @@ templates.groupSSOReauthenticate = ctaTemplate({ } else { const passwordResetUrl = `${settings.siteUrl}/user/password/reset` return [ - `If you’re not currently logged in to Overleaf, you'll need to set a new password to reauthenticate.`, + `If you’re not currently logged in to ${settings.appName}, you’ll need to set a new password to reauthenticate.`, ] } }, @@ -556,9 +556,9 @@ templates.groupSSOReauthenticate = ctaTemplate({ templates.groupSSODisabled = ctaTemplate({ subject(opts) { if (opts.userIsManaged) { - return `Action required: Set your Overleaf password` + return `Action required: Set your ${settings.appName} password` } else { - return 'A change to your Overleaf login options' + return `A change to your ${settings.appName} login options` } }, title(opts) { @@ -567,12 +567,12 @@ templates.groupSSODisabled = ctaTemplate({ message(opts, isPlainText) { const loginUrl = `${settings.siteUrl}/login` let whatDoesThisMeanExplanation = [ - `You can still log in to Overleaf using one of our other login options or with your email address and password.`, + `You can still log in to ${settings.appName} using one of our other login options or with your email address and password.`, `If you don't have a password, you can set one now.`, ] if (opts.userIsManaged) { whatDoesThisMeanExplanation = [ - 'You now need an email address and password to sign in to your Overleaf account.', + `You now need an email address and password to sign in to your ${settings.appName} account.`, ] } @@ -626,7 +626,7 @@ templates.surrenderAccountForManagedUsers = ctaTemplate({ const managedUsersLink = EmailMessageHelper.displayLink( 'user account management', - `${settings.siteUrl}/learn/how-to/Understanding_Managed_Overleaf_Accounts`, + `${settings.siteUrl}/learn/how-to/Understanding_Managed_Accounts`, isPlainText ) @@ -757,22 +757,17 @@ templates.userOnboardingEmail = NoCTAEmailTemplate({ message(opts, isPlainText) { const learnLatexLink = EmailMessageHelper.displayLink( 'Learn LaTeX in 30 minutes', - `${settings.siteUrl}/learn/latex/Learn_LaTeX_in_30_minutes?utm_source=overleaf&utm_medium=email&utm_campaign=onboarding`, + `${settings.siteUrl}/learn/latex/Learn_LaTeX_in_30_minutes?utm_source=verso&utm_medium=email&utm_campaign=onboarding`, isPlainText ) const templatesLinks = EmailMessageHelper.displayLink( 'Find a beautiful template', - `${settings.siteUrl}/latex/templates?utm_source=overleaf&utm_medium=email&utm_campaign=onboarding`, + `${settings.siteUrl}/latex/templates?utm_source=verso&utm_medium=email&utm_campaign=onboarding`, isPlainText ) const collaboratorsLink = EmailMessageHelper.displayLink( 'Work with your collaborators', - `${settings.siteUrl}/learn/how-to/Sharing_a_project?utm_source=overleaf&utm_medium=email&utm_campaign=onboarding`, - isPlainText - ) - const siteLink = EmailMessageHelper.displayLink( - 'www.overleaf.com', - settings.siteUrl, + `${settings.siteUrl}/learn/how-to/Sharing_a_project?utm_source=verso&utm_medium=email&utm_campaign=onboarding`, isPlainText ) const userSettingsLink = EmailMessageHelper.displayLink( @@ -780,28 +775,21 @@ templates.userOnboardingEmail = NoCTAEmailTemplate({ `${settings.siteUrl}/user/email-preferences`, isPlainText ) - const onboardingSurveyLink = EmailMessageHelper.displayLink( - 'Join our user feedback program', - 'https://forms.gle/DB7pdk2B1VFQqVVB9', - isPlainText - ) return [ `Thanks for signing up for ${settings.appName} recently. We hope you've been finding it useful! Here are some key features to help you get the most out of the service:`, `${learnLatexLink}: In this tutorial we provide a quick and easy first introduction to LaTeX with no prior knowledge required. By the time you are finished, you will have written your first LaTeX document!`, `${templatesLinks}: If you're looking for a template or example to get started, we've a large selection available in our template gallery, including CVs, project reports, journal articles and more.`, - `${collaboratorsLink}: One of the key features of Overleaf is the ability to share projects and collaborate on them with other users. Find out how to share your projects with your colleagues in this quick how-to guide.`, - `${onboardingSurveyLink} to help us make Overleaf even better!`, - 'Thanks again for using Overleaf :)', - `Lee`, - `Lee Shalit
CEO
${siteLink}
`, - `You're receiving this email because you've recently signed up for an Overleaf account. If you've previously subscribed to emails about product offers and company news and events, you can unsubscribe ${userSettingsLink}.`, + `${collaboratorsLink}: One of the key features of ${settings.appName} is the ability to share projects and collaborate on them with other users. Find out how to share your projects with your colleagues in this quick how-to guide.`, + `Thanks for using ${settings.appName}!`, + `The ${settings.appName} Team
`, + `You're receiving this email because you've recently signed up for a ${settings.appName} account. If you've previously subscribed to emails about product offers and company news and events, you can unsubscribe ${userSettingsLink}.`, ] }, }) templates.securityAlert = NoCTAEmailTemplate({ subject(opts) { - return `Overleaf security note: ${opts.action}` + return `${settings.appName} security note: ${opts.action}` }, title(opts) { return opts.action.charAt(0).toUpperCase() + opts.action.slice(1) @@ -837,12 +825,11 @@ templates.securityAlert = NoCTAEmailTemplate({ }, }) -const GIT_TOKEN_DOCS_URL = - 'https://docs.overleaf.com/integrations-and-add-ons/git-integration-and-github-synchronization/git-integration/git-integration-authentication-tokens#how-to-generate-authentication-tokens' +const GIT_TOKEN_DOCS_URL = `${settings.siteUrl}/learn/how-to/Git_integration` templates.gitTokenExpiringSoon = NoCTAEmailTemplate({ subject() { - return 'Your Overleaf token is about to expire' + return `Your ${settings.appName} token is about to expire` }, title() { return 'Your token is about to expire' @@ -866,14 +853,14 @@ templates.gitTokenExpiringSoon = NoCTAEmailTemplate({ `If you haven't already, you'll need to generate a new token in your ${settingsLink}.`, `Take a look at ${docsLink} if you need more help.`, 'All the best,', - 'Team Overleaf', + `The ${settings.appName} Team`, ] }, }) templates.gitTokenExpired = NoCTAEmailTemplate({ subject() { - return 'Your Overleaf token has expired' + return `Your ${settings.appName} token has expired` }, title() { return 'Token expired' @@ -897,7 +884,7 @@ templates.gitTokenExpired = NoCTAEmailTemplate({ `If you haven't already, you'll need to generate a new token in your ${settingsLink}.`, `Take a look at ${docsLink} if you need more help.`, 'All the best,', - 'Team Overleaf', + `The ${settings.appName} Team`, ] }, }) @@ -1040,7 +1027,7 @@ templates.removeGroupMember = NoCTAEmailTemplate({ templates.taxExemptCertificateRequired = NoCTAEmailTemplate({ subject(opts) { - return `Action required: Tax exemption verification for Overleaf [${opts.ein}]` + return `Action required: Tax exemption verification for ${settings.appName} [${opts.ein}]` }, title() { return 'Action required: Tax exemption verification' @@ -1060,7 +1047,7 @@ templates.taxExemptCertificateRequired = NoCTAEmailTemplate({ 'If you have any questions, let us know by replying to this email.', '
', 'Best wishes,', - 'Team Overleaf', + `The ${settings.appName} Team`, '
', `Our reference: ${opts.stripeCustomerId}`, ] @@ -1069,17 +1056,17 @@ templates.taxExemptCertificateRequired = NoCTAEmailTemplate({ templates.groupMemberLimitWarning = ctaTemplate({ subject(opts) { - return `Action needed: Your Overleaf group is nearly out of licenses` + return `Action needed: Your ${settings.appName} group is nearly out of licenses` }, title(opts) { - return `Action needed: Your Overleaf group is nearly out of licenses` + return `Action needed: Your ${settings.appName} group is nearly out of licenses` }, greeting(opts) { return opts.firstName ? `Hi ${opts.firstName},` : 'Hi there,' }, message(opts) { return [ - `Your Overleaf group ${opts.groupName} is close to its license limit.`, + `Your ${settings.appName} group ${opts.groupName} is close to its license limit.`, `${opts.currentMembers} of ${opts.membersLimit} licenses are in use (${opts.remainingSeats} remaining).`, 'Because domain capture is enabled, users from your domain can join automatically via SSO.' + '
' + diff --git a/services/web/app/src/Features/Email/Layouts/UpdatedBaseEmailLayout.mjs b/services/web/app/src/Features/Email/Layouts/UpdatedBaseEmailLayout.mjs index 174bd6d8d1..f7dc4aea7a 100644 --- a/services/web/app/src/Features/Email/Layouts/UpdatedBaseEmailLayout.mjs +++ b/services/web/app/src/Features/Email/Layouts/UpdatedBaseEmailLayout.mjs @@ -60,8 +60,8 @@ export default _.template(`\ .email-layout-table { border-collapse: collapse !important; } a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; } - .force-overleaf-style a, - .force-overleaf-style a[href] { + .force-verso-style a, + .force-verso-style a[href] { color: ${colors.linkGreen} !important; text-decoration: underline !important; -moz-hyphens: none; @@ -69,10 +69,10 @@ export default _.template(`\ -webkit-hyphens: none; hyphens: none; } - .force-overleaf-style a:visited, - .force-overleaf-style a[href]:visited { color: ${colors.linkGreen}; } - .force-overleaf-style a:hover, - .force-overleaf-style a[href]:hover { color: ${colors.linkHover}; } + .force-verso-style a:visited, + .force-verso-style a[href]:visited { color: ${colors.linkGreen}; } + .force-verso-style a:hover, + .force-verso-style a[href]:hover { color: ${colors.linkHover}; } @media only screen and (min-width: 621px) { .email-card-inner { padding: 56px !important; } @@ -149,7 +149,7 @@ export default _.template(`\ <% if (footerMessage) { %> - + <%= footerMessage %> diff --git a/services/web/app/src/Features/Email/emailStyles.mjs b/services/web/app/src/Features/Email/emailStyles.mjs index 5ad855e6c2..8f6f0e5dae 100644 --- a/services/web/app/src/Features/Email/emailStyles.mjs +++ b/services/web/app/src/Features/Email/emailStyles.mjs @@ -4,9 +4,9 @@ export const colors = { textDark: '#1b222c', textMuted: '#495365', background: '#f4f5f6', - ctaGreen: '#098842', + ctaGreen: '#2a9d8f', ctaText: '#ffffff', - linkGreen: '#1e6b41', - linkHover: '#155a30', - logoGreen: '#04652f', + linkGreen: '#1d7a6e', + linkHover: '#155e55', + logoGreen: '#2a9d8f', } diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 5b223a2816..2b588d174c 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -1018,6 +1018,7 @@ "institution_templates": "", "integrations": "", "integrations_like_github": "", + "interface_language": "", "interested_in_cheaper_personal_plan": "", "invalid_confirmation_code": "", "invalid_email": "", diff --git a/services/web/frontend/js/features/project-list/components/new-project-button.tsx b/services/web/frontend/js/features/project-list/components/new-project-button.tsx index 0ef374ead4..54af2ee177 100644 --- a/services/web/frontend/js/features/project-list/components/new-project-button.tsx +++ b/services/web/frontend/js/features/project-list/components/new-project-button.tsx @@ -67,8 +67,7 @@ function NewProjectButton({ const markdownImportEnabled = useFeatureFlag('import-markdown') && getMeta('ol-ExposedSettings').enablePandocConversions - const typstImportEnabled = getMeta('ol-ExposedSettings').enablePandocConversions - const { selectedTagId, tags } = useProjectListContext() +const { selectedTagId, tags } = useProjectListContext() const isLibraryEnabled = isSplitTestEnabled('overleaf-library') const initialTags = isLibraryEnabled && selectedTagId @@ -303,21 +302,6 @@ function NewProjectButton({ )} - {typstImportEnabled && ( -
  • - - handleModalMenuClick(e, { - modalVariant: 'import_typst', - dropdownMenuEvent: 'import-typst', - }) - } - trailingIcon={} - > - {t('import_typst_file')} - -
  • - )}
  • {ImportProjectFromGithubMenu && (