Email rebranding, mobile filter alignment fix, minor UI cleanup
Build and Deploy Verso / deploy (push) Has been cancelled
Build and Deploy Verso / deploy (push) Has been cancelled
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 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ export default _.template(`\
|
|||||||
<tr style="padding: 0; text-align: left; vertical-align: top;">
|
<tr style="padding: 0; text-align: left; vertical-align: top;">
|
||||||
<th style="margin: 0; padding: 0; text-align: left;">
|
<th style="margin: 0; padding: 0; text-align: left;">
|
||||||
<% if (title) { %>
|
<% if (title) { %>
|
||||||
<h3 class="force-overleaf-style" style="margin: 0; color: #5D6879; font-family: Georgia, serif; font-size: 24px; font-weight: normal; line-height: 1.3; padding: 0; text-align: left; word-wrap: normal;">
|
<h3 class="force-verso-style" style="margin: 0; color: #5D6879; font-family: Georgia, serif; font-size: 24px; font-weight: normal; line-height: 1.3; padding: 0; text-align: left; word-wrap: normal;">
|
||||||
<%= title %>
|
<%= title %>
|
||||||
</h3>
|
</h3>
|
||||||
<% } %>
|
<% } %>
|
||||||
@@ -25,7 +25,7 @@ export default _.template(`\
|
|||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% (message).forEach(function(paragraph) { %>
|
<% (message).forEach(function(paragraph) { %>
|
||||||
<p class="force-overleaf-style" style="margin: 0 0 10px 0; padding: 0;">
|
<p class="force-verso-style" style="margin: 0 0 10px 0; padding: 0;">
|
||||||
<%= paragraph %>
|
<%= paragraph %>
|
||||||
</p>
|
</p>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default _.template(`\
|
|||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% (message).forEach(function(paragraph) { %>
|
<% (message).forEach(function(paragraph) { %>
|
||||||
<p class="force-overleaf-style" style="margin: 0 0 16px 0;">
|
<p class="force-verso-style" style="margin: 0 0 16px 0;">
|
||||||
<%= paragraph %>
|
<%= paragraph %>
|
||||||
</p>
|
</p>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default _.template(`\
|
|||||||
<tr style="padding: 0; text-align: left; vertical-align: top;">
|
<tr style="padding: 0; text-align: left; vertical-align: top;">
|
||||||
<th style="margin: 0; padding: 0; text-align: left;">
|
<th style="margin: 0; padding: 0; text-align: left;">
|
||||||
<% if (title) { %>
|
<% if (title) { %>
|
||||||
<h3 class="force-overleaf-style" style="margin: 0; color: #5D6879; font-family: Georgia, serif; font-size: 24px; font-weight: normal; line-height: 1.3; padding: 0; text-align: left; word-wrap: normal;">
|
<h3 class="force-verso-style" style="margin: 0; color: #5D6879; font-family: Georgia, serif; font-size: 24px; font-weight: normal; line-height: 1.3; padding: 0; text-align: left; word-wrap: normal;">
|
||||||
<%= title %>
|
<%= title %>
|
||||||
</h3>
|
</h3>
|
||||||
<% } %>
|
<% } %>
|
||||||
@@ -25,7 +25,7 @@ export default _.template(`\
|
|||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% (message).forEach(function(paragraph) { %>
|
<% (message).forEach(function(paragraph) { %>
|
||||||
<p class="force-overleaf-style" style="margin: 0 0 10px 0; padding: 0;">
|
<p class="force-verso-style" style="margin: 0 0 10px 0; padding: 0;">
|
||||||
<%= paragraph %>
|
<%= paragraph %>
|
||||||
</p>
|
</p>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
@@ -52,7 +52,7 @@ export default _.template(`\
|
|||||||
<p style="margin: 0; padding: 0;"> </p>
|
<p style="margin: 0; padding: 0;"> </p>
|
||||||
|
|
||||||
<% (secondaryMessage).forEach(function(paragraph) { %>
|
<% (secondaryMessage).forEach(function(paragraph) { %>
|
||||||
<p class="force-overleaf-style">
|
<p class="force-verso-style">
|
||||||
<%= paragraph %>
|
<%= paragraph %>
|
||||||
</p>
|
</p>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
@@ -60,11 +60,11 @@ export default _.template(`\
|
|||||||
|
|
||||||
<p style="margin: 0; padding: 0;"> </p>
|
<p style="margin: 0; padding: 0;"> </p>
|
||||||
|
|
||||||
<p class="force-overleaf-style" style="font-size: 12px;">
|
<p class="force-verso-style" style="font-size: 12px;">
|
||||||
If the button above does not appear, please copy and paste this link into your browser's address bar:
|
If the button above does not appear, please copy and paste this link into your browser's address bar:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="force-overleaf-style" style="font-size: 12px;">
|
<p class="force-verso-style" style="font-size: 12px;">
|
||||||
<%= ctaURL %>
|
<%= ctaURL %>
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default _.template(`\
|
|||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% (message).forEach(function(paragraph) { %>
|
<% (message).forEach(function(paragraph) { %>
|
||||||
<p class="force-overleaf-style" style="margin: 0 0 16px 0;">
|
<p class="force-verso-style" style="margin: 0 0 16px 0;">
|
||||||
<%= paragraph %>
|
<%= paragraph %>
|
||||||
</p>
|
</p>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
@@ -32,7 +32,7 @@ export default _.template(`\
|
|||||||
|
|
||||||
<% if (secondaryMessage && secondaryMessage.length > 0) { %>
|
<% if (secondaryMessage && secondaryMessage.length > 0) { %>
|
||||||
<% (secondaryMessage).forEach(function(paragraph) { %>
|
<% (secondaryMessage).forEach(function(paragraph) { %>
|
||||||
<p class="force-overleaf-style" style="margin: 0 0 16px 0;">
|
<p class="force-verso-style" style="margin: 0 0 16px 0;">
|
||||||
<%= paragraph %>
|
<%= paragraph %>
|
||||||
</p>
|
</p>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ templates.confirmCode = NoCTAEmailTemplate({
|
|||||||
return ''
|
return ''
|
||||||
},
|
},
|
||||||
subject(opts) {
|
subject(opts) {
|
||||||
return `Confirm your email address on Overleaf (${opts.confirmCode})`
|
return `Confirm your email address on ${settings.appName} (${opts.confirmCode})`
|
||||||
},
|
},
|
||||||
title(opts) {
|
title(opts) {
|
||||||
return 'Confirm your email address'
|
return 'Confirm your email address'
|
||||||
@@ -284,7 +284,7 @@ templates.confirmCode = NoCTAEmailTemplate({
|
|||||||
message(opts, isPlainText) {
|
message(opts, isPlainText) {
|
||||||
const msg = opts.welcomeUser
|
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 confirmation code to finish your setup.',
|
||||||
]
|
]
|
||||||
: ['Use this 6-digit code to confirm your email address.']
|
: ['Use this 6-digit code to confirm your email address.']
|
||||||
@@ -477,7 +477,7 @@ templates.inviteNewUserToJoinManagedUsers = ctaTemplate({
|
|||||||
templates.groupSSOLinkingInvite = ctaTemplate({
|
templates.groupSSOLinkingInvite = ctaTemplate({
|
||||||
subject(opts) {
|
subject(opts) {
|
||||||
const subjectPrefix = opts.reminder ? 'Reminder: ' : 'Action required: '
|
const subjectPrefix = opts.reminder ? 'Reminder: ' : 'Action required: '
|
||||||
return `${subjectPrefix}Authenticate your Overleaf account`
|
return `${subjectPrefix}Authenticate your ${settings.appName} account`
|
||||||
},
|
},
|
||||||
title(opts) {
|
title(opts) {
|
||||||
const titlePrefix = opts.reminder ? 'Reminder: ' : ''
|
const titlePrefix = opts.reminder ? 'Reminder: ' : ''
|
||||||
@@ -495,8 +495,8 @@ templates.groupSSOLinkingInvite = ctaTemplate({
|
|||||||
</div>
|
</div>
|
||||||
</br>
|
</br>
|
||||||
<div>
|
<div>
|
||||||
You won't need to remember a separate email address and password to sign in to Overleaf.
|
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 Overleaf account with your SSO provider.
|
All you need to do is authenticate your existing ${settings.appName} account with your SSO provider.
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
]
|
]
|
||||||
@@ -517,7 +517,7 @@ templates.groupSSOLinkingInvite = ctaTemplate({
|
|||||||
|
|
||||||
templates.groupSSOReauthenticate = ctaTemplate({
|
templates.groupSSOReauthenticate = ctaTemplate({
|
||||||
subject(opts) {
|
subject(opts) {
|
||||||
return 'Action required: Reauthenticate your Overleaf account'
|
return \`Action required: Reauthenticate your \${settings.appName} account\`
|
||||||
},
|
},
|
||||||
title(opts) {
|
title(opts) {
|
||||||
return 'Action required: Reauthenticate SSO'
|
return 'Action required: Reauthenticate SSO'
|
||||||
@@ -526,8 +526,8 @@ templates.groupSSOReauthenticate = ctaTemplate({
|
|||||||
return [
|
return [
|
||||||
`Hi,
|
`Hi,
|
||||||
<div>
|
<div>
|
||||||
Single sign-on for your Overleaf group has been updated.
|
Single sign-on for your ${settings.appName} group has been updated.
|
||||||
This means you need to reauthenticate your Overleaf account with your group’s SSO provider.
|
This means you need to reauthenticate your ${settings.appName} account with your group’s SSO provider.
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
]
|
]
|
||||||
@@ -538,7 +538,7 @@ templates.groupSSOReauthenticate = ctaTemplate({
|
|||||||
} else {
|
} else {
|
||||||
const passwordResetUrl = `${settings.siteUrl}/user/password/reset`
|
const passwordResetUrl = `${settings.siteUrl}/user/password/reset`
|
||||||
return [
|
return [
|
||||||
`If you’re not currently logged in to Overleaf, you'll need to <a href="${passwordResetUrl}">set a new password</a> to reauthenticate.`,
|
`If you’re not currently logged in to ${settings.appName}, you’ll need to <a href="${passwordResetUrl}">set a new password</a> to reauthenticate.`,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -556,9 +556,9 @@ templates.groupSSOReauthenticate = ctaTemplate({
|
|||||||
templates.groupSSODisabled = ctaTemplate({
|
templates.groupSSODisabled = ctaTemplate({
|
||||||
subject(opts) {
|
subject(opts) {
|
||||||
if (opts.userIsManaged) {
|
if (opts.userIsManaged) {
|
||||||
return `Action required: Set your Overleaf password`
|
return `Action required: Set your ${settings.appName} password`
|
||||||
} else {
|
} else {
|
||||||
return 'A change to your Overleaf login options'
|
return `A change to your ${settings.appName} login options`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title(opts) {
|
title(opts) {
|
||||||
@@ -567,12 +567,12 @@ templates.groupSSODisabled = ctaTemplate({
|
|||||||
message(opts, isPlainText) {
|
message(opts, isPlainText) {
|
||||||
const loginUrl = `${settings.siteUrl}/login`
|
const loginUrl = `${settings.siteUrl}/login`
|
||||||
let whatDoesThisMeanExplanation = [
|
let whatDoesThisMeanExplanation = [
|
||||||
`You can still log in to Overleaf using one of our other <a href="${loginUrl}" style="color: #0F7A06; text-decoration: none;">login options</a> or with your email address and password.`,
|
`You can still log in to ${settings.appName} using one of our other <a href="${loginUrl}" style="color: #1d7a6e; text-decoration: none;">login options</a> or with your email address and password.`,
|
||||||
`If you don't have a password, you can set one now.`,
|
`If you don't have a password, you can set one now.`,
|
||||||
]
|
]
|
||||||
if (opts.userIsManaged) {
|
if (opts.userIsManaged) {
|
||||||
whatDoesThisMeanExplanation = [
|
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(
|
const managedUsersLink = EmailMessageHelper.displayLink(
|
||||||
'user account management',
|
'user account management',
|
||||||
`${settings.siteUrl}/learn/how-to/Understanding_Managed_Overleaf_Accounts`,
|
`${settings.siteUrl}/learn/how-to/Understanding_Managed_Accounts`,
|
||||||
isPlainText
|
isPlainText
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -757,22 +757,17 @@ templates.userOnboardingEmail = NoCTAEmailTemplate({
|
|||||||
message(opts, isPlainText) {
|
message(opts, isPlainText) {
|
||||||
const learnLatexLink = EmailMessageHelper.displayLink(
|
const learnLatexLink = EmailMessageHelper.displayLink(
|
||||||
'Learn LaTeX in 30 minutes',
|
'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
|
isPlainText
|
||||||
)
|
)
|
||||||
const templatesLinks = EmailMessageHelper.displayLink(
|
const templatesLinks = EmailMessageHelper.displayLink(
|
||||||
'Find a beautiful template',
|
'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
|
isPlainText
|
||||||
)
|
)
|
||||||
const collaboratorsLink = EmailMessageHelper.displayLink(
|
const collaboratorsLink = EmailMessageHelper.displayLink(
|
||||||
'Work with your collaborators',
|
'Work with your collaborators',
|
||||||
`${settings.siteUrl}/learn/how-to/Sharing_a_project?utm_source=overleaf&utm_medium=email&utm_campaign=onboarding`,
|
`${settings.siteUrl}/learn/how-to/Sharing_a_project?utm_source=verso&utm_medium=email&utm_campaign=onboarding`,
|
||||||
isPlainText
|
|
||||||
)
|
|
||||||
const siteLink = EmailMessageHelper.displayLink(
|
|
||||||
'www.overleaf.com',
|
|
||||||
settings.siteUrl,
|
|
||||||
isPlainText
|
isPlainText
|
||||||
)
|
)
|
||||||
const userSettingsLink = EmailMessageHelper.displayLink(
|
const userSettingsLink = EmailMessageHelper.displayLink(
|
||||||
@@ -780,28 +775,21 @@ templates.userOnboardingEmail = NoCTAEmailTemplate({
|
|||||||
`${settings.siteUrl}/user/email-preferences`,
|
`${settings.siteUrl}/user/email-preferences`,
|
||||||
isPlainText
|
isPlainText
|
||||||
)
|
)
|
||||||
const onboardingSurveyLink = EmailMessageHelper.displayLink(
|
|
||||||
'Join our user feedback program',
|
|
||||||
'https://forms.gle/DB7pdk2B1VFQqVVB9',
|
|
||||||
isPlainText
|
|
||||||
)
|
|
||||||
return [
|
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:`,
|
`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!`,
|
`${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.`,
|
`${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.`,
|
`${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.`,
|
||||||
`${onboardingSurveyLink} to help us make Overleaf even better!`,
|
`Thanks for using ${settings.appName}!`,
|
||||||
'Thanks again for using Overleaf :)',
|
`The ${settings.appName} Team<hr>`,
|
||||||
`Lee`,
|
`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}.`,
|
||||||
`Lee Shalit<br />CEO<br />${siteLink}<hr>`,
|
|
||||||
`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}.`,
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
templates.securityAlert = NoCTAEmailTemplate({
|
templates.securityAlert = NoCTAEmailTemplate({
|
||||||
subject(opts) {
|
subject(opts) {
|
||||||
return `Overleaf security note: ${opts.action}`
|
return `${settings.appName} security note: ${opts.action}`
|
||||||
},
|
},
|
||||||
title(opts) {
|
title(opts) {
|
||||||
return opts.action.charAt(0).toUpperCase() + opts.action.slice(1)
|
return opts.action.charAt(0).toUpperCase() + opts.action.slice(1)
|
||||||
@@ -837,12 +825,11 @@ templates.securityAlert = NoCTAEmailTemplate({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const GIT_TOKEN_DOCS_URL =
|
const GIT_TOKEN_DOCS_URL = `${settings.siteUrl}/learn/how-to/Git_integration`
|
||||||
'https://docs.overleaf.com/integrations-and-add-ons/git-integration-and-github-synchronization/git-integration/git-integration-authentication-tokens#how-to-generate-authentication-tokens'
|
|
||||||
|
|
||||||
templates.gitTokenExpiringSoon = NoCTAEmailTemplate({
|
templates.gitTokenExpiringSoon = NoCTAEmailTemplate({
|
||||||
subject() {
|
subject() {
|
||||||
return 'Your Overleaf token is about to expire'
|
return `Your ${settings.appName} token is about to expire`
|
||||||
},
|
},
|
||||||
title() {
|
title() {
|
||||||
return 'Your token is about to expire'
|
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}.`,
|
`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.`,
|
`Take a look at ${docsLink} if you need more help.`,
|
||||||
'All the best,',
|
'All the best,',
|
||||||
'Team Overleaf',
|
`The ${settings.appName} Team`,
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
templates.gitTokenExpired = NoCTAEmailTemplate({
|
templates.gitTokenExpired = NoCTAEmailTemplate({
|
||||||
subject() {
|
subject() {
|
||||||
return 'Your Overleaf token has expired'
|
return `Your ${settings.appName} token has expired`
|
||||||
},
|
},
|
||||||
title() {
|
title() {
|
||||||
return 'Token expired'
|
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}.`,
|
`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.`,
|
`Take a look at ${docsLink} if you need more help.`,
|
||||||
'All the best,',
|
'All the best,',
|
||||||
'Team Overleaf',
|
`The ${settings.appName} Team`,
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -1040,7 +1027,7 @@ templates.removeGroupMember = NoCTAEmailTemplate({
|
|||||||
|
|
||||||
templates.taxExemptCertificateRequired = NoCTAEmailTemplate({
|
templates.taxExemptCertificateRequired = NoCTAEmailTemplate({
|
||||||
subject(opts) {
|
subject(opts) {
|
||||||
return `Action required: Tax exemption verification for Overleaf [${opts.ein}]`
|
return `Action required: Tax exemption verification for ${settings.appName} [${opts.ein}]`
|
||||||
},
|
},
|
||||||
title() {
|
title() {
|
||||||
return 'Action required: Tax exemption verification'
|
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.',
|
'If you have any questions, let us know by replying to this email.',
|
||||||
'<br/>',
|
'<br/>',
|
||||||
'Best wishes,',
|
'Best wishes,',
|
||||||
'Team Overleaf',
|
`The ${settings.appName} Team`,
|
||||||
'<br/>',
|
'<br/>',
|
||||||
`Our reference: ${opts.stripeCustomerId}`,
|
`Our reference: ${opts.stripeCustomerId}`,
|
||||||
]
|
]
|
||||||
@@ -1069,17 +1056,17 @@ templates.taxExemptCertificateRequired = NoCTAEmailTemplate({
|
|||||||
|
|
||||||
templates.groupMemberLimitWarning = ctaTemplate({
|
templates.groupMemberLimitWarning = ctaTemplate({
|
||||||
subject(opts) {
|
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) {
|
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) {
|
greeting(opts) {
|
||||||
return opts.firstName ? `Hi ${opts.firstName},` : 'Hi there,'
|
return opts.firstName ? `Hi ${opts.firstName},` : 'Hi there,'
|
||||||
},
|
},
|
||||||
message(opts) {
|
message(opts) {
|
||||||
return [
|
return [
|
||||||
`Your Overleaf group <b>${opts.groupName}</b> is close to its license limit.`,
|
`Your ${settings.appName} group <b>${opts.groupName}</b> is close to its license limit.`,
|
||||||
`<b>${opts.currentMembers} of ${opts.membersLimit} licenses are in use (${opts.remainingSeats} remaining).</b>`,
|
`<b>${opts.currentMembers} of ${opts.membersLimit} licenses are in use (${opts.remainingSeats} remaining).</b>`,
|
||||||
'Because domain capture is enabled, users from your domain can join automatically via SSO.' +
|
'Because domain capture is enabled, users from your domain can join automatically via SSO.' +
|
||||||
'<br/>' +
|
'<br/>' +
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ export default _.template(`\
|
|||||||
.email-layout-table { border-collapse: collapse !important; }
|
.email-layout-table { border-collapse: collapse !important; }
|
||||||
a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }
|
a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }
|
||||||
|
|
||||||
.force-overleaf-style a,
|
.force-verso-style a,
|
||||||
.force-overleaf-style a[href] {
|
.force-verso-style a[href] {
|
||||||
color: ${colors.linkGreen} !important;
|
color: ${colors.linkGreen} !important;
|
||||||
text-decoration: underline !important;
|
text-decoration: underline !important;
|
||||||
-moz-hyphens: none;
|
-moz-hyphens: none;
|
||||||
@@ -69,10 +69,10 @@ export default _.template(`\
|
|||||||
-webkit-hyphens: none;
|
-webkit-hyphens: none;
|
||||||
hyphens: none;
|
hyphens: none;
|
||||||
}
|
}
|
||||||
.force-overleaf-style a:visited,
|
.force-verso-style a:visited,
|
||||||
.force-overleaf-style a[href]:visited { color: ${colors.linkGreen}; }
|
.force-verso-style a[href]:visited { color: ${colors.linkGreen}; }
|
||||||
.force-overleaf-style a:hover,
|
.force-verso-style a:hover,
|
||||||
.force-overleaf-style a[href]:hover { color: ${colors.linkHover}; }
|
.force-verso-style a[href]:hover { color: ${colors.linkHover}; }
|
||||||
|
|
||||||
@media only screen and (min-width: 621px) {
|
@media only screen and (min-width: 621px) {
|
||||||
.email-card-inner { padding: 56px !important; }
|
.email-card-inner { padding: 56px !important; }
|
||||||
@@ -149,7 +149,7 @@ export default _.template(`\
|
|||||||
|
|
||||||
<% if (footerMessage) { %>
|
<% if (footerMessage) { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" class="force-overleaf-style" style="padding: 0 0 32px 0; font-family: ${fontFamily}; font-size: 14px; color: ${colors.textMuted}; line-height: 20px;">
|
<td align="center" class="force-verso-style" style="padding: 0 0 32px 0; font-family: ${fontFamily}; font-size: 14px; color: ${colors.textMuted}; line-height: 20px;">
|
||||||
<%= footerMessage %>
|
<%= footerMessage %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ export const colors = {
|
|||||||
textDark: '#1b222c',
|
textDark: '#1b222c',
|
||||||
textMuted: '#495365',
|
textMuted: '#495365',
|
||||||
background: '#f4f5f6',
|
background: '#f4f5f6',
|
||||||
ctaGreen: '#098842',
|
ctaGreen: '#2a9d8f',
|
||||||
ctaText: '#ffffff',
|
ctaText: '#ffffff',
|
||||||
linkGreen: '#1e6b41',
|
linkGreen: '#1d7a6e',
|
||||||
linkHover: '#155a30',
|
linkHover: '#155e55',
|
||||||
logoGreen: '#04652f',
|
logoGreen: '#2a9d8f',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1018,6 +1018,7 @@
|
|||||||
"institution_templates": "",
|
"institution_templates": "",
|
||||||
"integrations": "",
|
"integrations": "",
|
||||||
"integrations_like_github": "",
|
"integrations_like_github": "",
|
||||||
|
"interface_language": "",
|
||||||
"interested_in_cheaper_personal_plan": "",
|
"interested_in_cheaper_personal_plan": "",
|
||||||
"invalid_confirmation_code": "",
|
"invalid_confirmation_code": "",
|
||||||
"invalid_email": "",
|
"invalid_email": "",
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ function NewProjectButton({
|
|||||||
const markdownImportEnabled =
|
const markdownImportEnabled =
|
||||||
useFeatureFlag('import-markdown') &&
|
useFeatureFlag('import-markdown') &&
|
||||||
getMeta('ol-ExposedSettings').enablePandocConversions
|
getMeta('ol-ExposedSettings').enablePandocConversions
|
||||||
const typstImportEnabled = getMeta('ol-ExposedSettings').enablePandocConversions
|
|
||||||
const { selectedTagId, tags } = useProjectListContext()
|
const { selectedTagId, tags } = useProjectListContext()
|
||||||
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
|
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
|
||||||
const initialTags =
|
const initialTags =
|
||||||
@@ -303,21 +302,6 @@ function NewProjectButton({
|
|||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
{typstImportEnabled && (
|
|
||||||
<li role="none">
|
|
||||||
<DropdownItem
|
|
||||||
onClick={e =>
|
|
||||||
handleModalMenuClick(e, {
|
|
||||||
modalVariant: 'import_typst',
|
|
||||||
dropdownMenuEvent: 'import-typst',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
trailingIcon={<MaterialIcon type="fiber_new" />}
|
|
||||||
>
|
|
||||||
{t('import_typst_file')}
|
|
||||||
</DropdownItem>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
<li role="none">
|
<li role="none">
|
||||||
{ImportProjectFromGithubMenu && (
|
{ImportProjectFromGithubMenu && (
|
||||||
<ImportProjectFromGithubMenu
|
<ImportProjectFromGithubMenu
|
||||||
|
|||||||
@@ -977,74 +977,65 @@ $lum-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' wi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Mobile toolbar: filter pills + zoom control ───────────────────────────
|
// ── Mobile toolbar: filter tabs + zoom control ───────────────────────────
|
||||||
|
// Two-row layout: filter tabs on top (wrapping), zoom on bottom-right.
|
||||||
// ── Mobile toolbar: tab-bar filters + zoom buttons ───────────────────────
|
// flex-wrap:wrap on the filter container is unconditionally safe (no
|
||||||
// Single row — filters scroll horizontally, zoom group is fixed on the right.
|
// overflow-x:auto ancestor chain needed). flex:1 1 auto on each tab makes
|
||||||
// The header is flex-direction:column on mobile so the toolbar has a definite
|
// all tabs in the same row equal-width regardless of label length, so the
|
||||||
// width; overflow-x:auto on the filters is safe and doesn't leak into the page.
|
// rows align cleanly without producing page overflow on narrow screens.
|
||||||
|
|
||||||
.lumiere-mobile-toolbar {
|
.lumiere-mobile-toolbar {
|
||||||
align-items: stretch;
|
flex-direction: column;
|
||||||
gap: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
flex-wrap: nowrap;
|
gap: 0.2rem;
|
||||||
border-bottom: 1.5px solid $lum-border;
|
padding: 0.1rem 0 0.4rem;
|
||||||
margin-bottom: 0.25rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lumiere-mobile-filters {
|
.lumiere-mobile-filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: wrap;
|
||||||
overflow-x: auto;
|
gap: 0.15rem;
|
||||||
scrollbar-width: none;
|
width: 100%;
|
||||||
-ms-overflow-style: none;
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar { display: none; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lumiere-mobile-zoom {
|
.lumiere-mobile-zoom {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
align-self: flex-end;
|
||||||
align-items: center;
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
border-left: 1.5px solid $lum-border;
|
|
||||||
margin: 0.3rem 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tab-style filter buttons — underline on active, no background/pill shape
|
// Filter tabs: equal-width per row, teal underline on active
|
||||||
.lumiere-mobile-filter-pill {
|
.lumiere-mobile-filter-pill {
|
||||||
flex-shrink: 0;
|
flex: 1 1 auto;
|
||||||
padding: 0.5rem 0.75rem;
|
text-align: center;
|
||||||
font-size: 0.8rem;
|
padding: 0.35rem 0.4rem;
|
||||||
|
font-size: 0.78rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: 1.5px solid $lum-border;
|
||||||
border-bottom: 2px solid transparent;
|
border-radius: 8px;
|
||||||
margin-bottom: -1.5px; // sit the active underline flush with the toolbar border
|
|
||||||
color: $lum-text-sub;
|
color: $lum-text-sub;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
line-height: 1.3;
|
line-height: 1.35;
|
||||||
transition: color 0.15s ease, border-color 0.15s ease;
|
transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: $lum-teal;
|
color: $lum-teal;
|
||||||
border-bottom-color: $lum-teal;
|
border-color: rgba($lum-teal, 0.45);
|
||||||
|
background: rgba($lum-teal, 0.07);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(.active),
|
&:hover:not(.active),
|
||||||
&:focus:not(.active) {
|
&:focus:not(.active) {
|
||||||
|
border-color: rgba($lum-teal, 0.2);
|
||||||
color: $lum-text;
|
color: $lum-text;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
outline: 2px solid rgba($lum-teal, 0.4);
|
outline: 2px solid rgba($lum-teal, 0.4);
|
||||||
outline-offset: -2px;
|
outline-offset: -1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user