Prettier for PUG templates (#26170)

* Setup prettier

* Ignore these pug templates by prettier

* Fix typo

* Fix prettier error

* Add prettier-ignore for quoting of event-segmentation attribute

* Manual tab indentation

* Interpolate

* Remove unbuffered if conditional

* Inline event-segmentation objects and remove prettier-ignore rule

* Fix spacing before interpolation

* Source format

* Source format

GitOrigin-RevId: c30e037f5caf8f91efc1bd9e75f81ae533b5a506
This commit is contained in:
Rebeka Dekany
2025-06-23 10:08:08 +02:00
committed by Copybot
parent 19dc71f414
commit c40ab3234d
96 changed files with 2140 additions and 1758 deletions

28
package-lock.json generated
View File

@@ -8911,6 +8911,33 @@
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@prettier/plugin-pug": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@prettier/plugin-pug/-/plugin-pug-3.4.0.tgz",
"integrity": "sha512-Jzd5rE/ellJz3vqfxyVewPsCHXw1dmIzJ3AXhAnqVBKQOj2u73ZS2oUacji8CbQSsYyCy7GXFjXWDlDTMG1x2g==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/Shinigami92"
},
{
"type": "paypal",
"url": "https://www.paypal.com/donate/?hosted_button_id=L7GY729FBKTZY"
}
],
"license": "MIT",
"dependencies": {
"pug-lexer": "^5.0.1"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
},
"peerDependencies": {
"prettier": "^3.0.0"
}
},
"node_modules/@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
@@ -45272,6 +45299,7 @@
"@pollyjs/adapter-node-http": "^6.0.6",
"@pollyjs/core": "^6.0.6",
"@pollyjs/persister-fs": "^6.0.6",
"@prettier/plugin-pug": "^3.4.0",
"@replit/codemirror-emacs": "overleaf/codemirror-emacs#4394c03858f27053f8768258e9493866e06e938e",
"@replit/codemirror-indentation-markers": "overleaf/codemirror-indentation-markers#78264032eb286bc47871569ae87bff5ca1c6c161",
"@replit/codemirror-vim": "overleaf/codemirror-vim#1bef138382d948018f3f9b8a4d7a70ab61774e4b",

View File

@@ -13,3 +13,28 @@ frontend/js/features/source-editor/lezer-latex/latex.terms.mjs
frontend/js/features/source-editor/lezer-bibtex/bibtex.mjs
frontend/js/features/source-editor/lezer-bibtex/bibtex.terms.mjs
frontend/js/features/source-editor/hunspell/wasm/hunspell.mjs
# complex pages
app/views/project/editor.pug
app/views/project/editor/**
modules/open-in-overleaf/app/views/documentation.pug
modules/references-search/app/views/project/editor/**
modules/rich-text/app/views/toolbar.pug
# loops
app/views/referal/bonus.pug
modules/templates/app/views/tag.pug
# expressions that could not be formatted correctly
app/views/_mixins/faq_search.pug
app/views/external/home/v2.pug
app/views/project/token/access.pug
app/views/user/primaryEmailCheck.pug
app/views/user/restricted.pug
modules/admin-panel/app/views/project/show.pug
modules/templates/app/views/project/editor/_left-menu.pug
modules/two-factor-authentication/app/views/_mixins.pug
# minified files
app/views/_google_analytics.pug
app/views/_customer_io.pug

View File

@@ -1,9 +1,23 @@
{
"arrowParens": "avoid",
"jsxSingleQuote": false,
"pugAttributeSeparator": "as-needed",
"pugBracketSpacing": false,
"pugClassNotation": "as-is",
"pugIdNotation": "as-is",
"pugSortAttributesBeginning": ["name", "data-type"],
"plugins": ["@prettier/plugin-pug"],
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false
"useTabs": false,
"overrides": [
{
"files": "*.pug",
"options": {
"useTabs": true
}
}
]
}

View File

@@ -455,12 +455,19 @@ format: format_styles
format_styles:
npm run --silent format:styles
format: format_pug
format_pug:
npm run --silent format:pug
format_fix:
npm run --silent format:fix
format_styles_fix:
npm run --silent format:styles:fix
format_pug_fix:
npm run --silent format:pug:fix
format_in_docker:
$(RUN_LINT_FORMAT) make format -j2 --output-sync

View File

@@ -1,5 +1,13 @@
section.cookie-banner.hidden-print.hidden(aria-label="Cookie banner")
.cookie-banner-content We only use cookies for essential purposes and to improve your experience on our site. You can find out more in our <a href="/legal#Cookies">cookie policy</a>.
.cookie-banner-actions
button(type="button" class="btn btn-link btn-sm" data-ol-cookie-banner-set-consent="essential") Essential cookies only
button(type="button" class="btn btn-primary btn-sm" data-ol-cookie-banner-set-consent="all") Accept all cookies
section.cookie-banner.hidden-print.hidden(aria-label='Cookie banner')
.cookie-banner-content We only use cookies for essential purposes and to improve your experience on our site. You can find out more in our <a href="/legal#Cookies">cookie policy</a>.
.cookie-banner-actions
button(
type='button'
class='btn btn-link btn-sm'
data-ol-cookie-banner-set-consent='essential'
) Essential cookies only
button(
type='button'
class='btn btn-primary btn-sm'
data-ol-cookie-banner-set-consent='all'
) Accept all cookies

View File

@@ -1,123 +1,140 @@
//- Title
if (metadata && metadata.title)
title= metadata.title + ' - ' + settings.appName + ', ' + translate("online_latex_editor")
meta(name="twitter:title", content=metadata.title)
meta(name="og:title", content=metadata.title)
else if (typeof(title) == "undefined")
title= settings.appName + ', '+ translate("online_latex_editor")
meta(name="twitter:title", content=settings.appName + ', '+ translate("online_latex_editor"))
meta(name="og:title", content=settings.appName + ', '+ translate("online_latex_editor"))
if metadata && metadata.title
title= metadata.title + ' - ' + settings.appName + ', ' + translate('online_latex_editor')
meta(name='twitter:title' content=metadata.title)
meta(name='og:title' content=metadata.title)
else if typeof title == 'undefined'
title= settings.appName + ', ' + translate('online_latex_editor')
meta(
name='twitter:title'
content=settings.appName + ', ' + translate('online_latex_editor')
)
meta(
name='og:title'
content=settings.appName + ', ' + translate('online_latex_editor')
)
else
title= translate(title) + ' - ' + settings.appName + ', ' + translate("online_latex_editor")
title= translate(title) + ' - ' + settings.appName + ', ' + translate('online_latex_editor')
//- to do - not translate?
meta(name="twitter:title", content=translate(title))
meta(name="og:title", content=translate(title))
meta(name='twitter:title' content=translate(title))
meta(name='og:title' content=translate(title))
//- Description
if (metadata && metadata.description)
meta(name="description" , content=metadata.description)
meta(itemprop="description" , content=metadata.description)
if metadata && metadata.description
meta(name='description' content=metadata.description)
meta(itemprop='description' content=metadata.description)
//-twitter and og descriptions handeled in their sections below
else
meta(name="description", content=translate("site_description"))
meta(itemprop="description", content=translate("site_description"))
meta(name='description' content=translate('site_description'))
meta(itemprop='description' content=translate('site_description'))
//- Image
if (metadata && metadata.image && metadata.image.fields)
if metadata && metadata.image && metadata.image.fields
//- from the CMS
meta(itemprop="image", content=metadata.image.fields.file.url)
meta(name="image", content=metadata.image.fields.file.url)
else if (metadata && metadata.image_src)
meta(itemprop='image' content=metadata.image.fields.file.url)
meta(name='image' content=metadata.image.fields.file.url)
else if metadata && metadata.image_src
//- pages with custom metadata images, metadata.image_src is the full image URL
meta(itemprop="image", content=metadata.image_src)
meta(name="image", content=metadata.image_src)
else if (settings.overleaf)
meta(itemprop='image' content=metadata.image_src)
meta(name='image' content=metadata.image_src)
else if settings.overleaf
//- the default image for Overleaf
meta(itemprop="image", content=buildImgPath('ol-brand/overleaf_og_logo.png'))
meta(name="image", content=buildImgPath('ol-brand/overleaf_og_logo.png'))
meta(itemprop='image' content=buildImgPath('ol-brand/overleaf_og_logo.png'))
meta(name='image' content=buildImgPath('ol-brand/overleaf_og_logo.png'))
else
//- the default image for Overleaf Community Edition/Server Pro
meta(itemprop="image", content='/apple-touch-icon.png')
meta(name="image", content='/apple-touch-icon.png')
meta(itemprop='image' content='/apple-touch-icon.png')
meta(name='image' content='/apple-touch-icon.png')
//- Keywords
if (metadata && metadata.keywords)
meta(name="keywords" content=metadata.keywords)
if metadata && metadata.keywords
meta(name='keywords' content=metadata.keywords)
//- Misc
meta(itemprop="name", content=settings.appName + ", the Online LaTeX Editor")
meta(itemprop='name' content=settings.appName + ', the Online LaTeX Editor')
if (metadata && metadata.robotsNoindexNofollow)
meta(name="robots" content="noindex, nofollow")
if metadata && metadata.robotsNoindexNofollow
meta(name='robots' content='noindex, nofollow')
//- Twitter
meta(name="twitter:card", content=metadata && metadata.twitterCardType ? metadata.twitterCardType : 'summary')
if (settings.social && settings.social.twitter && settings.social.twitter.handle)
meta(name="twitter:site", content="@" + settings.social.twitter.handle)
if (metadata && metadata.twitterDescription)
meta(name="twitter:description", content=metadata.twitterDescription)
meta(
name='twitter:card'
content=metadata && metadata.twitterCardType ? metadata.twitterCardType : 'summary'
)
if settings.social && settings.social.twitter && settings.social.twitter.handle
meta(name='twitter:site' content='@' + settings.social.twitter.handle)
if metadata && metadata.twitterDescription
meta(name='twitter:description' content=metadata.twitterDescription)
else
meta(name="twitter:description", content=translate("site_description"))
if (metadata && metadata.twitterImage && metadata.twitterImage.fields)
meta(name='twitter:description' content=translate('site_description'))
if metadata && metadata.twitterImage && metadata.twitterImage.fields
//- from the CMS
meta(name="twitter:image", content=metadata.twitterImage.fields.file.url)
meta(name="twitter:image:alt", content=metadata.twitterImage.fields.title)
else if (settings.overleaf)
meta(name='twitter:image' content=metadata.twitterImage.fields.file.url)
meta(name='twitter:image:alt' content=metadata.twitterImage.fields.title)
else if settings.overleaf
//- the default image for Overleaf
meta(name="twitter:image", content=buildImgPath('ol-brand/overleaf_og_logo.png'))
meta(
name='twitter:image'
content=buildImgPath('ol-brand/overleaf_og_logo.png')
)
else
//- the default image for Overleaf Community Edition/Server Pro
meta(name="twitter:image", content='/apple-touch-icon.png')
meta(name='twitter:image' content='/apple-touch-icon.png')
//- Open Graph
//- to do - add og:url
if (settings.social && settings.social.facebook && settings.social.facebook.appId)
meta(property="fb:app_id", content=settings.social.facebook.appId)
if settings.social && settings.social.facebook && settings.social.facebook.appId
meta(property='fb:app_id' content=settings.social.facebook.appId)
if (metadata && metadata.openGraphDescription)
meta(property="og:description", content=metadata.openGraphDescription)
if metadata && metadata.openGraphDescription
meta(property='og:description' content=metadata.openGraphDescription)
else
meta(property="og:description", content=translate("site_description"))
meta(property='og:description' content=translate('site_description'))
if (metadata && metadata.openGraphImage && metadata.openGraphImage.fields)
if metadata && metadata.openGraphImage && metadata.openGraphImage.fields
//- from the CMS
meta(property="og:image", content=metadata.openGraphImage.fields.file.url)
else if (settings.overleaf)
meta(property='og:image' content=metadata.openGraphImage.fields.file.url)
else if settings.overleaf
//- the default image for Overleaf
meta(property="og:image", content=buildImgPath('ol-brand/overleaf_og_logo.png'))
meta(
property='og:image'
content=buildImgPath('ol-brand/overleaf_og_logo.png')
)
else
//- the default image for Overleaf Community Edition/Server Pro
meta(property="og:image", content='/apple-touch-icon.png')
meta(property='og:image' content='/apple-touch-icon.png')
if (metadata && metadata.openGraphType)
meta(property="og:type", metadata.openGraphType)
if metadata && metadata.openGraphType
meta(property='og:type' metadata.openGraphType)
else
meta(property="og:type", content="website")
meta(property='og:type' content='website')
if (metadata && metadata.openGraphVideo)
if metadata && metadata.openGraphVideo
//- from the CMS
meta(property="og:video", content=metadata.openGraphVideo)
meta(property='og:video' content=metadata.openGraphVideo)
//- Viewport
if !metadata || metadata.viewport !== false
meta(name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes")
meta(
name='viewport'
content='width=device-width, initial-scale=1.0, user-scalable=yes'
)
//- Noindex
if settings.robotsNoindex
meta(name="robots" content="noindex")
meta(name='robots' content='noindex')
//- Icons
link(rel="icon", sizes="32x32", href="/favicon-32x32.png")
link(rel="icon", sizes="16x16", href="/favicon-16x16.png")
link(rel="icon", href="/favicon.svg" type="image/svg+xml")
link(rel="apple-touch-icon", href="/apple-touch-icon.png")
link(rel="mask-icon", href="/mask-favicon.svg", color="#046530")
link(rel='icon' sizes='32x32' href='/favicon-32x32.png')
link(rel='icon' sizes='16x16' href='/favicon-16x16.png')
link(rel='icon' href='/favicon.svg' type='image/svg+xml')
link(rel='apple-touch-icon' href='/apple-touch-icon.png')
link(rel='mask-icon' href='/mask-favicon.svg' color='#046530')
//- Canonical Tag for SEO
if (metadata && metadata.canonicalURL)
link(rel="canonical" href=metadata.canonicalURL)
if metadata && metadata.canonicalURL
link(rel='canonical' href=metadata.canonicalURL)
//- Manifest
//- Does not currently contain a start_url to prevent browser installation prompts
link(rel="manifest" href="/web.sitemanifest")
link(rel='manifest' href='/web.sitemanifest')

View File

@@ -1,4 +1,6 @@
mixin back-to-btns(settingsAnchor)
.d-flex.flex-column.flex-sm-row.gap-3
a.btn.btn-secondary(href=`/user/settings${settingsAnchor ? '#' + settingsAnchor : '' }`) #{translate('back_to_account_settings')}
a.btn.btn-secondary(
href=`/user/settings${settingsAnchor ? '#' + settingsAnchor : '' }`
) #{translate('back_to_account_settings')}
a.btn.btn-secondary(href='/project') #{translate('back_to_your_projects')}

View File

@@ -1,10 +1,10 @@
mixin begin_now_card()
mixin begin_now_card
- var registerURL = '/register'
- var plansURL = '/user/subscription/plans'
- var isUserLoggedIn = !!getSessionUser()
.begin-now-card
div.card.card-pattern
.card.card-pattern
.card-body
p.dm-mono
span.font-size-display-xs
@@ -16,10 +16,8 @@ mixin begin_now_card()
p #{translate("discover_why_over_people_worldwide_trust_overleaf", {count: settings.userCountInMillions})}
p.card-links
if !isUserLoggedIn
a.btn.btn-primary.card-link(
href=registerURL
) #{translate("sign_up_for_free")}
a.btn.btn-primary.card-link(href=registerURL) #{translate("sign_up_for_free")}
a.btn.card-link(
class = isUserLoggedIn ? 'btn-primary' : 'btn-secondary'
class=isUserLoggedIn ? 'btn-primary' : 'btn-secondary'
href=plansURL
) #{translate("explore_all_plans")}

View File

@@ -1,10 +1,10 @@
mixin bookmarkable-tabset-header(id, title, active)
li(role="presentation")
li(role='presentation')
a.nav-link(
href='#' + id
class=(active ? 'active' : '')
class=active ? 'active' : ''
aria-controls=id
role="tab"
data-toggle="tab"
role='tab'
data-toggle='tab'
data-ol-bookmarkable-tab
) #{title}

View File

@@ -1,3 +1,3 @@
mixin bootstrap-js(bootstrapVersion)
each file in (entrypointScripts(bootstrapVersion === 5 ? 'bootstrap-5' : 'bootstrap-3'))
script(type="text/javascript", nonce=scriptNonce, src=file)
each file in entrypointScripts(bootstrapVersion === 5 ? 'bootstrap-5' : 'bootstrap-3')
script(type='text/javascript' nonce=scriptNonce src=file)

View File

@@ -1,5 +1,5 @@
mixin eyebrow(text)
span.eyebrow-text
span(aria-hidden="true") {
span #{text}
span(aria-hidden="true") }
span.eyebrow-text
span(aria-hidden='true') {
span #{text}
span(aria-hidden='true') }

View File

@@ -1,30 +1,37 @@
mixin faq_search-marketing(headerText, headerClass)
if (typeof(settings.algolia) != "undefined" && typeof(settings.algolia.indexes) != "undefined" && typeof(settings.algolia.indexes.wiki) != "undefined")
if typeof settings.algolia != 'undefined' && typeof settings.algolia.indexes != 'undefined' && typeof settings.algolia.indexes.wiki != 'undefined'
if headerText
div(class=headerClass) #{headerText}
.wiki
form.project-search.form-horizontal(role="search" data-ol-faq-search)
form.project-search.form-horizontal(role='search' data-ol-faq-search)
.form-group.has-feedback.has-feedback-left
.col-sm-12
input.form-control(type='search', placeholder="Search help library…" aria-label="Search help library…")
i.fa.fa-search.form-control-feedback-left(aria-hidden="true")
input.form-control(
type='search'
placeholder='Search help library…'
aria-label='Search help library…'
)
i.fa.fa-search.form-control-feedback-left(aria-hidden='true')
i.fa.fa-times.form-control-feedback(
style="cursor: pointer;",
style='cursor: pointer'
hidden
data-ol-clear-search
aria-hidden="true"
aria-hidden='true'
)
button.sr-only(
type="button"
type='button'
hidden
data-ol-clear-search
aria-label=translate('clear_search')
)
.row(role="region" aria-label="search results")
.col-md-12()
.row(role='region' aria-label='search results')
.col-md-12
div(data-ol-search-results-wrapper)
span.sr-only(aria-live="polite" data-ol-search-sr-help-message)
span.sr-only(aria-live='polite' data-ol-search-sr-help-message)
div(data-ol-search-results)
.row-spaced-small.search-result.card.card-thin(hidden data-ol-search-no-results)
.row-spaced-small.search-result.card.card-thin(
hidden
data-ol-search-no-results
)
p #{translate("no_search_results")}

View File

@@ -1,6 +1,11 @@
mixin foot-scripts()
mixin foot-scripts
each file in entrypointScripts(entrypoint)
script(type="text/javascript", nonce=scriptNonce, src=file, defer=deferScripts)
if (settings.devToolbar.enabled)
each file in entrypointScripts("devToolbar")
script(type="text/javascript", nonce=scriptNonce, src=file, defer=deferScripts)
script(type='text/javascript' nonce=scriptNonce src=file defer=deferScripts)
if settings.devToolbar.enabled
each file in entrypointScripts('devToolbar')
script(
type='text/javascript'
nonce=scriptNonce
src=file
defer=deferScripts
)

View File

@@ -1,41 +1,35 @@
include ./material_symbol
mixin formMessages()
div(
data-ol-form-messages='',
role="alert"
)
mixin formMessages
div(data-ol-form-messages='' role='alert')
mixin formMessagesNewStyle(extraClass = 'form-messages-bottom-margin')
- const attrs = extraClass ? { 'class': extraClass } : {}
div(
data-ol-form-messages-new-style='',
role="alert"
)&attributes(attrs)
- const attrs = extraClass ? {class: extraClass} : {}
div(data-ol-form-messages-new-style='' role='alert')&attributes(attrs)
mixin customFormMessage(key, kind)
if kind === 'success'
div.alert.alert-success(
hidden,
data-ol-custom-form-message=key,
role="alert"
aria-live="polite"
.alert.alert-success(
hidden
data-ol-custom-form-message=key
role='alert'
aria-live='polite'
)
block
else if kind === 'danger'
div.alert.alert-danger(
hidden,
data-ol-custom-form-message=key,
role="alert"
aria-live="assertive"
.alert.alert-danger(
hidden
data-ol-custom-form-message=key
role='alert'
aria-live='assertive'
)
block
else
div.alert.alert-warning(
hidden,
data-ol-custom-form-message=key,
role="alert"
aria-live="polite"
.alert.alert-warning(
hidden
data-ol-custom-form-message=key
role='alert'
aria-live='polite'
)
block
@@ -43,56 +37,50 @@ mixin customFormMessageNewStyle(key, kind, extraClass = 'mb-3')
- extraClass = extraClass ? ' ' + extraClass : ''
if kind === 'success'
div(
class="notification notification-type-success" + extraClass,
hidden,
data-ol-custom-form-message=key,
role="alert"
aria-live="polite"
class='notification notification-type-success' + extraClass
hidden
data-ol-custom-form-message=key
role='alert'
aria-live='polite'
)
div.notification-icon
+material-symbol("check_circle")
div.notification-content.text-left
.notification-icon
+material-symbol('check_circle')
.notification-content.text-left
block
else if kind === 'danger'
div(
class="notification notification-type-error" + extraClass,
hidden,
data-ol-custom-form-message=key,
role="alert"
aria-live="polite"
class='notification notification-type-error' + extraClass
hidden
data-ol-custom-form-message=key
role='alert'
aria-live='polite'
)
div.notification-icon
+material-symbol("error")
div.notification-content.text-left
.notification-icon
+material-symbol('error')
.notification-content.text-left
block
else
div(
class="notification notification-type-warning" + extraClass,
hidden,
data-ol-custom-form-message=key,
role="alert"
aria-live="polite"
class='notification notification-type-warning' + extraClass
hidden
data-ol-custom-form-message=key
role='alert'
aria-live='polite'
)
div.notification-icon
+material-symbol("warning")
div.notification-content.text-left
.notification-icon
+material-symbol('warning')
.notification-content.text-left
block
mixin customValidationMessage(key)
div.invalid-feedback.mt-2(
hidden,
data-ol-custom-form-message=key
)
i.fa.fa-fw.fa-warning.me-1(aria-hidden="true")
.invalid-feedback.mt-2(hidden data-ol-custom-form-message=key)
i.fa.fa-fw.fa-warning.me-1(aria-hidden='true')
div
block
mixin customValidationMessageNewStyle(key)
div.notification.notification-type-error(
hidden,
data-ol-custom-form-message=key
)
div.notification-icon
+material-symbol("error")
div.notification-content.text-left.small
.notification.notification-type-error(hidden data-ol-custom-form-message=key)
.notification-icon
+material-symbol('error')
.notification-content.text-left.small
block

View File

@@ -8,7 +8,8 @@ mixin linkAdvisors(linkText, linkClass, track)
- var mb = track && track.mb ? 'true' : null
- var mbSegmentation = track && track.segmentation ? track.segmentation : null
- var trigger = track && track.trigger ? track.trigger : null
a(href="/advisors"
a(
href='/advisors'
class=linkClass ? linkClass : ''
event-tracking-ga=gaCategory
event-tracking=gaAction
@@ -20,24 +21,36 @@ mixin linkAdvisors(linkText, linkClass, track)
span #{linkText ? linkText : 'advisor programme'}
mixin linkBenefits(linkText, linkClass)
a(href=(settings.siteUrl ? settings.siteUrl : '') + "/for/authors" class=linkClass ? linkClass : '')
a(
href=(settings.siteUrl ? settings.siteUrl : '') + '/for/authors'
class=linkClass ? linkClass : ''
)
| #{linkText ? linkText : 'benefits'}
mixin linkBlog(linkText, linkClass, slug)
if slug
a(href=(settings.siteUrl ? settings.siteUrl : '') + "/blog/" + slug class=linkClass ? linkClass : '')
a(
href=(settings.siteUrl ? settings.siteUrl : '') + '/blog/' + slug
class=linkClass ? linkClass : ''
)
| #{linkText ? linkText : 'blog'}
mixin linkContact(linkText, linkClass)
a(href=(settings.siteUrl ? settings.siteUrl : '') + "/contact" class=linkClass ? linkClass : '')
a(
href=(settings.siteUrl ? settings.siteUrl : '') + '/contact'
class=linkClass ? linkClass : ''
)
| #{linkText ? linkText : 'contact'}
mixin linkDash(linkText, linkClass)
a(href="/project" class=linkClass ? linkClass : '')
a(href='/project' class=linkClass ? linkClass : '')
| #{linkText ? linkText : 'project dashboard'}
mixin linkEducation(linkText, linkClass)
a(href=(settings.siteUrl ? settings.siteUrl : '') + "/for/edu" class=linkClass ? linkClass : '')
a(
href=(settings.siteUrl ? settings.siteUrl : '') + '/for/edu'
class=linkClass ? linkClass : ''
)
| #{linkText ? linkText : 'teaching toolkit'}
mixin linkInvite(linkText, linkClass, track)
@@ -48,7 +61,8 @@ mixin linkInvite(linkText, linkClass, track)
- var mbSegmentation = track && track.segmentation ? track.segmentation : null
- var trigger = track && track.trigger ? track.trigger : null
a(href="/user/bonus"
a(
href='/user/bonus'
class=linkClass ? linkClass : ''
event-tracking-ga=gaCategory
event-tracking=gaAction
@@ -60,7 +74,7 @@ mixin linkInvite(linkText, linkClass, track)
span #{linkText ? linkText : 'invite your friends'}
mixin linkPlansAndPricing(linkText, linkClass)
a(href="/user/subscription/plans" class=linkClass ? linkClass : '')
a(href='/user/subscription/plans' class=linkClass ? linkClass : '')
| #{linkText ? linkText : 'plans and pricing'}
mixin linkPrintNewTab(linkText, linkClass, icon, track)
@@ -71,7 +85,8 @@ mixin linkPrintNewTab(linkText, linkClass, icon, track)
- var mbSegmentation = track && track.segmentation ? track.segmentation : null
- var trigger = track && track.trigger ? track.trigger : null
a(href='?media=print'
a(
href='?media=print'
class=linkClass ? linkClass : ''
event-tracking-ga=gaCategory
event-tracking=gaAction
@@ -79,20 +94,26 @@ mixin linkPrintNewTab(linkText, linkClass, icon, track)
event-tracking-trigger=trigger
event-tracking-mb=mb
event-segmentation=mbSegmentation
target="_BLANK",
rel="noopener noreferrer"
target='_BLANK'
rel='noopener noreferrer'
)
if icon
i(class="fa fa-print")
i(class='fa fa-print')
| &nbsp;
span #{linkText ? linkText : 'print'}
mixin linkSignIn(linkText, linkClass, redirect)
a(href=`/login${redirect ? '?redir=' + redirect : ''}` class=linkClass ? linkClass : '')
a(
href=`/login${redirect ? '?redir=' + redirect : ''}`
class=linkClass ? linkClass : ''
)
| #{linkText ? linkText : 'sign in'}
mixin linkSignUp(linkText, linkClass, redirect)
a(href=`/register${redirect ? '?redir=' + redirect : ''}` class=linkClass ? linkClass : '')
a(
href=`/register${redirect ? '?redir=' + redirect : ''}`
class=linkClass ? linkClass : ''
)
| #{linkText ? linkText : 'sign up'}
mixin linkTweet(linkText, linkClass, tweetText, track)
@@ -103,23 +124,33 @@ mixin linkTweet(linkText, linkClass, tweetText, track)
- var mb = track && track.mb ? 'true' : null
- var mbSegmentation = track && track.segmentation ? track.segmentation : null
- var trigger = track && track.trigger ? track.trigger : null
a(class="twitter-share-button " + linkClass
a(
class='twitter-share-button ' + linkClass
event-tracking-ga=gaCategory
event-tracking=gaAction
event-tracking-label=gaLabel
event-tracking-trigger=trigger
event-tracking-mb=mb
event-segmentation=mbSegmentation
href="https://twitter.com/intent/tweet?text=" + tweetText
target="_BLANK",
rel="noopener noreferrer"
href='https://twitter.com/intent/tweet?text=' + tweetText
target='_BLANK'
rel='noopener noreferrer'
) #{linkText ? linkText : 'tweet'}
mixin linkUniversities(linkText, linkClass)
a(href=(settings.siteUrl ? settings.siteUrl : '') + "/for/universities" class=linkClass ? linkClass : '')
a(
href=(settings.siteUrl ? settings.siteUrl : '') + '/for/universities'
class=linkClass ? linkClass : ''
)
| #{linkText ? linkText : 'universities'}
mixin linkWithArrow({text, href, eventTracking, eventSegmentation, eventTrackingTrigger})
a.link-with-arrow(href=href event-tracking=eventTracking event-segmentation=eventSegmentation, event-tracking-trigger=eventTrackingTrigger event-tracking-mb)
a.link-with-arrow(
href=href
event-tracking=eventTracking
event-segmentation=eventSegmentation
event-tracking-trigger=eventTrackingTrigger
event-tracking-mb
)
| #{text}
+material-symbol("arrow_right_alt")
+material-symbol('arrow_right_alt')

View File

@@ -1,7 +1,8 @@
mixin material-symbol(icon, extraClass = null)
- extraClass = extraClass ? ' ' + extraClass : ''
span(aria-hidden="true", translate="no", class="material-symbols" + extraClass)&attributes(attributes) #{icon}
span(aria-hidden='true' translate='no' class='material-symbols' + extraClass)&attributes(attributes)
| #{icon}
mixin material-symbol-outlined(icon, extraClass = null)
- extraClass = extraClass ? ' ' + extraClass : ''
+material-symbol(icon, 'material-symbols-outlined' + extraClass)&attributes(attributes)

View File

@@ -1,23 +1,23 @@
mixin nav-item
li(role="none")&attributes(attributes)
li(role='none')&attributes(attributes)
block
mixin nav-link
a(role="menuitem").nav-link&attributes(attributes)
a.nav-link(role='menuitem')&attributes(attributes)
block
mixin dropdown-menu
ul(role="menu").dropdown-menu&attributes(attributes)
ul.dropdown-menu(role='menu')&attributes(attributes)
block
mixin dropdown-menu-item
li(role="none")
li(role='none')
block
mixin dropdown-menu-link-item
+dropdown-menu-item
a(role="menuitem").dropdown-item&attributes(attributes)
a.dropdown-item(role='menuitem')&attributes(attributes)
block
mixin dropdown-menu-divider
li(role="separator").dropdown-divider.d-none.d-lg-block
li.dropdown-divider.d-none.d-lg-block(role='separator')

View File

@@ -3,25 +3,19 @@ include ./material_symbol
mixin notificationIcon(type)
if type === 'info'
+material-symbol("info")
+material-symbol('info')
else if type === 'success'
+material-symbol("check_circle")
+material-symbol('check_circle')
else if type === 'error'
+material-symbol("error")
+material-symbol('error')
else if type === 'warning'
+material-symbol("warning")
+material-symbol('warning')
mixin notification(options)
- var {ariaLive, id, type, title, content, disclaimer, className} = options
- var classNames = `notification notification-type-${type} ${className ? className : ''} ${isActionBelowContent ? 'notification-cta-below-content' : ''}`
div(
aria-live=ariaLive,
role="alert",
id=id,
class=classNames
)
div(aria-live=ariaLive role='alert' id=id class=classNames)
.notification-icon
+notificationIcon(type)
.notification-content-and-cta

View File

@@ -10,77 +10,74 @@ mixin pagination(pages, page_path, max_btns)
- var max_btns = max_btns || 4
- var prev_page = Math.max(parseInt(pages.current_page, 10) - max_btns, 1)
- var next_page = parseInt(pages.current_page, 10) + 1
- var next_index = 0;
- var full_page_path = page_path + "/page/"
- var next_index = 0
- var full_page_path = page_path + '/page/'
nav(role="navigation" aria-label=(translate("pagination_navigation")))
nav(role='navigation' aria-label=translate('pagination_navigation'))
ul.pagination
if pages.current_page > 1
li
a(
aria-label=translate("go_to_first_page")
href=page_path
)
span(aria-hidden="true") &lt;&lt;
a(aria-label=translate('go_to_first_page') href=page_path)
span(aria-hidden='true') &lt;&lt;
|
| First
li
a(
aria-label=translate("go_to_previous_page")
aria-label=translate('go_to_previous_page')
href=full_page_path + (parseInt(pages.current_page, 10) - 1)
rel="prev"
rel='prev'
)
span(aria-hidden="true") &lt;
span(aria-hidden='true') &lt;
|
| Prev
if pages.current_page - max_btns > 1
li(aria-hidden="true")
li(aria-hidden='true')
span …
while prev_page < pages.current_page
li
a(
aria-label=translate("go_to_page_x", {page: prev_page})
aria-label=translate('go_to_page_x', {page: prev_page})
href=full_page_path + prev_page
) #{prev_page}
- prev_page++
li(class="active")
li(class='active')
span(
aria-label=translate("current_page_page", {page: pages.current_page})
aria-current="true"
aria-label=translate('current_page_page', {page: pages.current_page})
aria-current='true'
) #{pages.current_page}
if pages.current_page < pages.total_pages
while next_page <= pages.total_pages && next_index < max_btns
li
a(
aria-label=translate("go_to_page_x", {page: next_page})
aria-label=translate('go_to_page_x', {page: next_page})
href=full_page_path + next_page
) #{next_page}
- next_page++
- next_index++
if next_page <= pages.total_pages
li.ellipses(aria-hidden="true")
if next_page <= pages.total_pages
li.ellipses(aria-hidden='true')
span …
li
a(
aria-label=translate("go_to_next_page")
aria-label=translate('go_to_next_page')
href=full_page_path + (parseInt(pages.current_page, 10) + 1)
rel="next"
rel='next'
)
| Next
|
span(aria-hidden="true") &gt;
span(aria-hidden='true') &gt;
li
a(
aria-label=translate("go_to_last_page")
aria-label=translate('go_to_last_page')
href=full_page_path + pages.total_pages
)
| Last
|
span(aria-hidden="true") &gt;&gt;
span(aria-hidden='true') &gt;&gt;

View File

@@ -2,5 +2,5 @@ include ./material_symbol
mixin previous-page-link(href, text)
a.previous-page-link(href=href)
+material-symbol-rounded("arrow_left_alt")
+material-symbol-rounded('arrow_left_alt')
| #{text}

View File

@@ -3,10 +3,10 @@ mixin quoteLargeTextCentered(quote, person, position, affiliation, link, picture
.quote !{quote}
if pictureUrl
.quote-img
-var pictureAlt=`Photo of ${person}`
- var pictureAlt = `Photo of ${person}`
img(src=pictureUrl alt=pictureAlt)
footer
div.quote-person
.quote-person
strong #{person}
if person && position
div #{position}
@@ -29,27 +29,27 @@ mixin quoteLeftGreenBorder({quote, person, position, affiliation, link})
mixin collinsQuote1
.card.card-dark-green-bg
-var quote = 'Overleaf is indispensable for us. We use it in our research, thesis writing, project proposals, and manuscripts for publication. When it comes to writing, its our main tool.'
-var quotePerson = 'Christopher Collins'
-var quotePersonPosition = 'Associate Professor and Lab Director, Ontario Tech University'
-var quotePersonImg = buildImgPath("advocates/collins.jpg")
- var quote = 'Overleaf is indispensable for us. We use it in our research, thesis writing, project proposals, and manuscripts for publication. When it comes to writing, its our main tool.'
- var quotePerson = 'Christopher Collins'
- var quotePersonPosition = 'Associate Professor and Lab Director, Ontario Tech University'
- var quotePersonImg = buildImgPath('advocates/collins.jpg')
.card-body
+quoteLargeTextCentered(quote, quotePerson, quotePersonPosition, null, null, quotePersonImg)
mixin collinsQuote2
.card.card-dark-green-bg
-var quote = 'We are writing collaboratively right up until the last minute. We are faced with deadlines all the time, and Overleaf gives us the ability to polish right up until the last possible second.'
-var quotePerson = 'Christopher Collins'
-var quotePersonPosition = 'Associate Professor and Lab Director, Ontario Tech University'
-var quotePersonImg = buildImgPath("advocates/collins.jpg")
- var quote = 'We are writing collaboratively right up until the last minute. We are faced with deadlines all the time, and Overleaf gives us the ability to polish right up until the last possible second.'
- var quotePerson = 'Christopher Collins'
- var quotePersonPosition = 'Associate Professor and Lab Director, Ontario Tech University'
- var quotePersonImg = buildImgPath('advocates/collins.jpg')
.card-body
+quoteLargeTextCentered(quote, quotePerson, quotePersonPosition, null, null, quotePersonImg)
mixin bennettQuote1
.card.card-dark-green-bg
-var quote = 'With Overleaf, we now have a process for developing technical documentation which has virtually eliminated the time required to properly format and layout documents.'
-var quotePerson = 'Andrew Bennett'
-var quotePersonPosition = 'Software Architect, Symplectic'
-var quotePersonImg = buildImgPath("advocates/bennett.jpg")
- var quote = 'With Overleaf, we now have a process for developing technical documentation which has virtually eliminated the time required to properly format and layout documents.'
- var quotePerson = 'Andrew Bennett'
- var quotePersonPosition = 'Software Architect, Symplectic'
- var quotePersonImg = buildImgPath('advocates/bennett.jpg')
.card-body
+quoteLargeTextCentered(quote, quotePerson, quotePersonPosition, null, null, quotePersonImg)

View File

@@ -1,2 +1,2 @@
mixin recaptchaConditions()
mixin recaptchaConditions
.recaptcha-branding !{translate("recaptcha_conditions", {}, [{}, {name: 'a', attrs: {href: 'https://policies.google.com/privacy', rel: 'noopener noreferrer', target: '_blank'}}, {name: 'a', attrs: {href: 'https://policies.google.com/terms', rel: 'noopener noreferrer', target: '_blank'}}])}

View File

@@ -1,14 +1,11 @@
mixin reconfirmAffiliationNotification-marketing(userEmail, location)
form(
data-ol-async-form
action='/user/emails/send-reconfirmation'
)
input(name="_csrf" type="hidden" value=csrfToken)
input(name="email" type="hidden" value=userEmail.email)
+formMessages()
form(data-ol-async-form action='/user/emails/send-reconfirmation')
input(name='_csrf' type='hidden' value=csrfToken)
input(name='email' type='hidden' value=userEmail.email)
+formMessages
.reconfirm-notification
div(data-ol-not-sent style="width:100%;")
div(data-ol-not-sent style='width: 100%')
i.fa.fa-warning
- var ssoEnabled = userEmail.affiliation && userEmail.affiliation.institution && userEmail.affiliation.institution.ssoEnabled
@@ -18,16 +15,16 @@ mixin reconfirmAffiliationNotification-marketing(userEmail, location)
data-ol-slow-link
href=`${settings.saml.ukamf.initPath}?university_id=${institutionId}&reconfirm=${location}`
)
span(data-ol-inflight="idle") #{translate("confirm_affiliation")}
span(hidden data-ol-inflight="pending") #{translate("pending")}…
span(data-ol-inflight='idle') #{translate("confirm_affiliation")}
span(hidden data-ol-inflight='pending') #{translate("pending")}…
else
button.btn-reconfirm.btn.btn-sm.btn-info(
type="submit"
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("confirm_affiliation")}
span(hidden data-ol-inflight="pending") #{translate("pending")}…
span(data-ol-inflight='idle') #{translate("confirm_affiliation")}
span(hidden data-ol-inflight='pending') #{translate("pending")}…
| !{translate("are_you_still_at", {institutionName: userEmail.affiliation.institution.name}, ['strong'])}&nbsp;
@@ -39,22 +36,19 @@ mixin reconfirmAffiliationNotification-marketing(userEmail, location)
| !{translate("please_reconfirm_institutional_email", {}, [{name: 'a', attrs: {href: '/user/settings?remove=' + userEmail.email}}])}
| &nbsp;
a(href="/learn/how-to/Institutional_Email_Reconfirmation" target="_blank") #{translate("learn_more")}
a(href='/learn/how-to/Institutional_Email_Reconfirmation' target='_blank') #{translate("learn_more")}
div(hidden data-ol-sent)
| !{translate("please_check_your_inbox_to_confirm", {institutionName: userEmail.affiliation.institution.name}, ['strong'])}
| &nbsp;
button.btn-inline-link(
type="submit"
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate('resend_confirmation_email')}
span(hidden data-ol-inflight="pending") #{translate("pending")}…
button.btn-inline-link(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate('resend_confirmation_email')}
span(hidden data-ol-inflight='pending') #{translate("pending")}…
mixin reconfirmedAffiliationNotification-marketing(userEmail)
.alert.alert-info
.reconfirm-notification
div(style="width:100%;")
div(style='width: 100%')
//- extra div for flex styling
| !{translate("your_affiliation_is_confirmed", {institutionName: userEmail.affiliation.institution.name}, ['strong'])}
|

View File

@@ -1,3 +1,3 @@
mixin termsOfServiceAgreement
div.tos-agreement-notice
.tos-agreement-notice
| !{translate("by_registering_you_agree_to_our_terms_of_service", {}, [{name: 'a', attrs: {href: '/legal#Terms', target: '_blank'}}, {name: 'a', attrs: {href: '/legal#Privacy', target: '_blank'}}])}

View File

@@ -2,7 +2,7 @@ extends ../layout-marketing
include ../_mixins/bookmarkable_tabset
block content
.content.content-alt#main-content
#main-content.content.content-alt
.container
.row
.col-sm-12
@@ -12,7 +12,7 @@ block content
h1 Admin Panel
.ol-tabs(data-ol-bookmarkable-tabset)
.nav-tabs-container
ul.nav.nav-tabs.align-left(role="tablist")
ul.nav.nav-tabs.align-left(role='tablist')
+bookmarkable-tabset-header('system-messages', 'System Messages', true)
+bookmarkable-tabset-header('open-sockets', 'Open Sockets')
+bookmarkable-tabset-header('open-close-editor', 'Open/Close Editor')
@@ -20,29 +20,28 @@ block content
+bookmarkable-tabset-header('tpds', 'TPDS/Dropbox Management')
.tab-content
.tab-pane.active(
role="tabpanel"
id='system-messages'
)
.tab-pane.active(role='tabpanel' id='system-messages')
each message in systemMessages
ul.system-messages
li.system-message.row-spaced #{message.content}
hr
form(method='post', action='/admin/messages')
input(name="_csrf", type="hidden", value=csrfToken)
form(method='post' action='/admin/messages')
input(name='_csrf' type='hidden' value=csrfToken)
.form-group
label.form-label(for="content")
input.form-control(name="content", type="text", placeholder="Message…", required)
button.btn.btn-primary(type="submit") Post Message
label.form-label(for='content')
input.form-control(
name='content'
type='text'
placeholder='Message…'
required
)
button.btn.btn-primary(type='submit') Post Message
hr
form(method='post', action='/admin/messages/clear')
input(name="_csrf", type="hidden", value=csrfToken)
button.btn.btn-danger(type="submit") Clear all messages
form(method='post' action='/admin/messages/clear')
input(name='_csrf' type='hidden' value=csrfToken)
button.btn.btn-danger(type='submit') Clear all messages
.tab-pane(
role="tabpanel"
id='open-sockets'
)
.tab-pane(role='tabpanel' id='open-sockets')
.row-spaced
ul
each agents, url in openSockets
@@ -51,52 +50,56 @@ block content
each agent in agents
li #{agent}
.tab-pane(
role="tabpanel"
id='open-close-editor'
)
.tab-pane(role='tabpanel' id='open-close-editor')
if hasFeature('saas')
| The "Open/Close Editor" feature is not available in SAAS.
else
.row-spaced
form(method='post',action='/admin/closeEditor')
input(name="_csrf", type="hidden", value=csrfToken)
button.btn.btn-danger(type="submit") Close Editor
form(method='post' action='/admin/closeEditor')
input(name='_csrf' type='hidden' value=csrfToken)
button.btn.btn-danger(type='submit') Close Editor
p.small Will stop anyone opening the editor. Will NOT disconnect already connected users.
.row-spaced
form(method='post',action='/admin/disconnectAllUsers')
input(name="_csrf", type="hidden", value=csrfToken)
button.btn.btn-danger(type="submit") Disconnect all users
form(method='post' action='/admin/disconnectAllUsers')
input(name='_csrf' type='hidden' value=csrfToken)
button.btn.btn-danger(type='submit') Disconnect all users
p.small Will force disconnect all users with the editor open. Make sure to close the editor first to avoid them reconnecting.
.row-spaced
form(method='post',action='/admin/openEditor')
input(name="_csrf", type="hidden", value=csrfToken)
button.btn.btn-danger(type="submit") Reopen Editor
form(method='post' action='/admin/openEditor')
input(name='_csrf' type='hidden' value=csrfToken)
button.btn.btn-danger(type='submit') Reopen Editor
p.small Will reopen the editor after closing.
if hasFeature('saas')
.tab-pane(
role="tabpanel"
id='tpds'
)
.tab-pane(role='tabpanel' id='tpds')
h3 Flush project to TPDS
.row
form.col-xs-6(method='post',action='/admin/flushProjectToTpds')
input(name="_csrf", type="hidden", value=csrfToken)
form.col-xs-6(method='post' action='/admin/flushProjectToTpds')
input(name='_csrf' type='hidden' value=csrfToken)
.form-group
label.form-label(for='project_id') project_id
input.form-control(type='text', name='project_id', placeholder='project_id', required)
input.form-control(
name='project_id'
type='text'
placeholder='project_id'
required
)
.form-group
button.btn-primary.btn(type='submit') Flush
hr
h3 Poll Dropbox for user
.row
form.col-xs-6(method='post',action='/admin/pollDropboxForUser')
input(name="_csrf", type="hidden", value=csrfToken)
form.col-xs-6(method='post' action='/admin/pollDropboxForUser')
input(name='_csrf' type='hidden' value=csrfToken)
.form-group
label.form-label(for='user_id') user_id
input.form-control(type='text', name='user_id', placeholder='user_id', required)
input.form-control(
name='user_id'
type='text'
placeholder='user_id'
required
)
.form-group
button.btn-primary.btn(type='submit') Poll

View File

@@ -2,14 +2,14 @@ extends ../layout-marketing
include ../_mixins/back_to_btns
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container.beta-opt-in-wrapper
.row
.col-lg-10.offset-lg-1.col-xl-8.offset-xl-2
.card
.card-body
.page-header
h1
h1
| #{translate("sharelatex_beta_program")}
.beta-opt-in
.container-fluid
@@ -28,7 +28,9 @@ block content
ul
li
| #{translate("beta_program_badge_description")}&nbsp;
span.badge.bg-warning-light-bg.text-warning(aria-label=translate("beta_feature_badge"))
span.badge.bg-warning-light-bg.text-warning(
aria-label=translate('beta_feature_badge')
)
span.badge-content β
li !{translate("you_will_be_able_to_contact_us_any_time_to_share_your_feedback", {}, ['strong'])}.
li !{translate("we_may_also_contact_you_from_time_to_time_by_email_with_a_survey", {}, ['strong'])}.
@@ -40,37 +42,30 @@ block content
if user.betaProgram
form(
data-ol-regular-form
method="post"
action="/beta/opt-out"
method='post'
action='/beta/opt-out'
novalidate
)
input(type="hidden", name="_csrf", value=csrfToken)
input(name='_csrf' type='hidden' value=csrfToken)
.form-group
a(
href="https://forms.gle/CFEsmvZQTAwHCd3X9"
target="_blank"
rel="noopener noreferrer"
).btn.btn-primary.btn-lg #{translate("give_feedback")}
a.btn.btn-primary.btn-lg(
href='https://forms.gle/CFEsmvZQTAwHCd3X9'
target='_blank'
rel='noopener noreferrer'
) #{translate("give_feedback")}
.form-group
button.btn.btn-secondary-info.btn-secondary.btn-sm(
type="submit"
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("beta_program_opt_out_action")}
span(hidden data-ol-inflight="pending") #{translate("processing")}…
span(data-ol-inflight='idle') #{translate("beta_program_opt_out_action")}
span(hidden data-ol-inflight='pending') #{translate("processing")}…
else
form(
data-ol-regular-form
method="post",
action="/beta/opt-in"
)
input(type="hidden", name="_csrf", value=csrfToken)
form(data-ol-regular-form method='post' action='/beta/opt-in')
input(name='_csrf' type='hidden' value=csrfToken)
.form-group
button.btn.btn-primary(
type="submit"
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("beta_program_opt_in_action")}
span(hidden data-ol-inflight="pending") #{translate("joining")}…
button.btn.btn-primary(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("beta_program_opt_in_action")}
span(hidden data-ol-inflight='pending') #{translate("joining")}…
.page-separator
+back-to-btns()
+back-to-btns

View File

@@ -1,29 +1,29 @@
extends ../layout/layout-no-js
block vars
- metadata = { title: 'Something went wrong' }
- metadata = {title: 'Something went wrong'}
block body
body.full-height
main.content.content-alt.full-height#main-content
main#main-content.content.content-alt.full-height
.container.full-height
.error-container.full-height
.error-details
p.error-status Something went wrong, sorry.
p.error-description
| There was a problem with your request.
if(message)
if message
|
| The error is:
if(message)
if message
p.error-box
| #{message}
p.error-description
| Please go back and try again.
| If the problem persists, please contact us at
|
a(href="mailto:" + settings.adminEmail) #{settings.adminEmail}
a(href='mailto:' + settings.adminEmail) #{settings.adminEmail}
| .
p.error-actions
a.error-btn(href="javascript:history.back()") Back
a.btn.btn-secondary(href="/") Home
a.error-btn(href='javascript:history.back()') Back
a.btn.btn-secondary(href='/') Home

View File

@@ -1,11 +1,11 @@
extends ../layout-marketing
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.error-container
.error-details
p.error-status Not found
p.error-description #{translate("cant_find_page")}
p.error-actions
a.error-btn(href="/") Home
a.error-btn(href='/') Home

View File

@@ -1,11 +1,11 @@
extends ../layout/layout-no-js
block vars
- metadata = { title: 'Something went wrong' }
- metadata = {title: 'Something went wrong'}
block body
body.full-height
main.content.content-alt.full-height#main-content
main#main-content.content.content-alt.full-height
.container.full-height
.error-container.full-height
.error-details
@@ -13,11 +13,11 @@ block body
p.error-description Our staff are probably looking into this, but if it continues, please check our status page at
|
|
a(href="http://" + settings.statusPageUrl) #{settings.statusPageUrl}
a(href='http://' + settings.statusPageUrl) #{settings.statusPageUrl}
|
| or contact us at
|
a(href="mailto:" + settings.adminEmail) #{settings.adminEmail}
a(href='mailto:' + settings.adminEmail) #{settings.adminEmail}
| .
p.error-actions
a.error-btn(href="/") Home
a.error-btn(href='/') Home

View File

@@ -1,7 +1,7 @@
extends ../layout-marketing
block content
main.content#main-content
main#main-content.content
.container
.row
.col-lg-8.offset-lg-2.text-center

View File

@@ -15,12 +15,8 @@ block content
.card-body
p.text-center #{translate('processing_your_request')}
form(
data-ol-regular-form
data-ol-auto-submit
method="POST"
)
input(name="_csrf" type="hidden" value=csrfToken)
input(hidden name="viaGateway" type="submit" value="true")
for name in Object.keys(form_data)
input(name=name type="hidden" value=form_data[name])
form(data-ol-regular-form data-ol-auto-submit method='POST')
input(name='_csrf' type='hidden' value=csrfToken)
input(name='viaGateway' hidden type='submit' value='true')
each name in Object.keys(form_data)
input(name=name type='hidden' value=form_data[name])

View File

@@ -1,11 +1,11 @@
extends ../layout/layout-no-js
block vars
- metadata = { title: 'Unsupported browser' }
- metadata = {title: 'Unsupported browser'}
block body
body.full-height
main.content.content-alt.full-height#main-content
main#main-content.content.content-alt.full-height
.container.full-height
.error-container.full-height
.error-details
@@ -15,7 +15,7 @@ block body
br
| If you think you're seeing this message in error,
|
a(href="mailto:" + settings.adminEmail) please let us know
a(href='mailto:' + settings.adminEmail) please let us know
| .
if fromURL
@@ -33,7 +33,7 @@ block body
p
| Support for beta or developer-preview browser versions cannot be guaranteed. Please
|
a(href="mailto:" + settings.adminEmail) get in touch
a(href='mailto:' + settings.adminEmail) get in touch
|
| if you encounter any issues while using the service with beta or developer-preview releases of supported browsers.
p
@@ -41,5 +41,5 @@ block body
p
| If you cannot upgrade to one of the supported browsers,
|
a(href="mailto:" + settings.adminEmail) please let us know
a(href='mailto:' + settings.adminEmail) please let us know
| .

View File

@@ -2,8 +2,8 @@ include ./_mixins/foot_scripts
doctype html
html(
lang=(currentLngCode || 'en')
class=(fixedSizeDocument ? 'fixed-size-document' : undefined)
lang=currentLngCode || 'en'
class=fixedSizeDocument ? 'fixed-size-document' : undefined
)
- metadata = metadata || {}
- let bootstrap5PageStatus = 'enabled' // One of 'disabled' and 'enabled'
@@ -22,91 +22,128 @@ html(
include ./_metadata.pug
- const bootstrapVersion = bootstrap5PageStatus !== 'disabled' && (bootstrap5Override || bootstrap5PageSplitTest === '' || splitTestVariants[bootstrap5PageSplitTest] === 'enabled') ? 5 : 3
//- Stylesheet
link(rel='stylesheet', href=buildCssPath(getCssThemeModifier(userSettings, brandVariation, enableIeeeBranding), bootstrapVersion), id="main-stylesheet")
link(
rel='stylesheet'
href=buildCssPath(getCssThemeModifier(userSettings, brandVariation, enableIeeeBranding), bootstrapVersion)
id='main-stylesheet'
)
block css
each file in entrypointStyles(entrypoint)
link(rel='stylesheet', href=file)
link(rel='stylesheet' href=file)
block _headLinks
if (typeof suppressRelAlternateLinks == "undefined")
if typeof suppressRelAlternateLinks == 'undefined'
if settings.i18n.subdomainLang
each subdomainDetails in settings.i18n.subdomainLang
if !subdomainDetails.hide
link(rel="alternate", href=subdomainDetails.url + currentUrl, hreflang=subdomainDetails.lngCode)
link(
rel='alternate'
href=subdomainDetails.url + currentUrl
hreflang=subdomainDetails.lngCode
)
if (entrypoint !== 'marketing')
link(rel="preload", href=buildJsPath(currentLngCode + "-json.js"), as="script", nonce=scriptNonce)
if entrypoint !== 'marketing'
link(
rel='preload'
href=buildJsPath(currentLngCode + '-json.js')
as='script'
nonce=scriptNonce
)
//- Scripts
if (typeof suppressGoogleAnalytics == "undefined")
if typeof suppressGoogleAnalytics == 'undefined'
include _google_analytics
block meta
meta(name="ol-csrfToken" content=csrfToken)
meta(name='ol-csrfToken' content=csrfToken)
//- Configure dynamically loaded assets (via webpack) to be downloaded from CDN
//- See: https://webpack.js.org/guides/public-path/#on-the-fly
meta(name="ol-baseAssetPath" content=buildBaseAssetPath())
meta(name="ol-mathJaxPath" content=mathJaxPath)
meta(name="ol-dictionariesRoot" content=dictionariesRoot)
meta(name='ol-baseAssetPath' content=buildBaseAssetPath())
meta(name='ol-mathJaxPath' content=mathJaxPath)
meta(name='ol-dictionariesRoot' content=dictionariesRoot)
meta(name="ol-usersEmail" content=getUserEmail())
meta(name="ol-ab" data-type="json" content={})
meta(name="ol-user_id" content=getLoggedInUserId())
meta(name='ol-usersEmail' content=getUserEmail())
meta(name='ol-ab' data-type='json' content={})
meta(name='ol-user_id' content=getLoggedInUserId())
//- Internationalisation settings
meta(name="ol-i18n" data-type="json" content={
currentLangCode: currentLngCode
})
meta(
name='ol-i18n'
data-type='json'
content={
currentLangCode: currentLngCode,
}
)
//- Expose some settings globally to the frontend
meta(name="ol-ExposedSettings" data-type="json" content=ExposedSettings)
meta(name="ol-splitTestVariants" data-type="json" content=splitTestVariants || {})
meta(name="ol-splitTestInfo" data-type="json" content=splitTestInfo || {})
meta(name='ol-ExposedSettings' data-type='json' content=ExposedSettings)
meta(
name='ol-splitTestVariants'
data-type='json'
content=splitTestVariants || {}
)
meta(name='ol-splitTestInfo' data-type='json' content=splitTestInfo || {})
if (typeof settings.algolia != "undefined")
meta(name="ol-algolia" data-type="json" content={
appId: settings.algolia.app_id,
apiKey: settings.algolia.read_only_api_key,
indexes: settings.algolia.indexes
})
if typeof settings.algolia != 'undefined'
meta(
name='ol-algolia'
data-type='json'
content={
appId: settings.algolia.app_id,
apiKey: settings.algolia.read_only_api_key,
indexes: settings.algolia.indexes,
}
)
meta(name="ol-isManagedAccount" data-type="boolean" content=isManagedAccount)
meta(
name='ol-isManagedAccount'
data-type='boolean'
content=isManagedAccount
)
each restriction in userRestrictions || []
meta(name='ol-cannot-' + restriction data-type="boolean" content=true)
meta(name="ol-bootstrapVersion" data-type="json" content=bootstrapVersion)
meta(name='ol-cannot-' + restriction data-type='boolean' content)
meta(name='ol-bootstrapVersion' data-type='json' content=bootstrapVersion)
block head-scripts
body(class={
'thin-footer': showThinFooter,
'website-redesign': isWebsiteRedesign === true || websiteRedesignOverride,
'application-page': isApplicationPage
}, data-theme="default")
if(settings.recaptcha && settings.recaptcha.siteKeyV3)
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render=" + settings.recaptcha.siteKeyV3, defer=deferScripts)
body(
class={
'thin-footer': showThinFooter,
'website-redesign': isWebsiteRedesign === true || websiteRedesignOverride,
'application-page': isApplicationPage,
}
data-theme='default'
)
if settings.recaptcha && settings.recaptcha.siteKeyV3
script(
type='text/javascript'
nonce=scriptNonce
src='https://www.recaptcha.net/recaptcha/api.js?render=' + settings.recaptcha.siteKeyV3
defer=deferScripts
)
if (typeof suppressSkipToContent == "undefined")
a(class="skip-to-content" href="#main-content") #{translate('skip_to_content')}
if typeof suppressSkipToContent == 'undefined'
a(class='skip-to-content' href='#main-content') #{translate('skip_to_content')}
block body
if (settings.devToolbar.enabled)
div#dev-toolbar
if settings.devToolbar.enabled
#dev-toolbar
block foot-scripts
+foot-scripts
include _customer_io
script(type="text/javascript", nonce=scriptNonce).
window.addEventListener('DOMContentLoaded', function() {
script(type='text/javascript' nonce=scriptNonce).
window.addEventListener('DOMContentLoaded', function () {
//- Look for bundle
var cdnBlocked = typeof Frontend === 'undefined'
//- Prevent loops
var noCdnAlreadyInUrl = window.location.href.indexOf("nocdn=true") != -1
if (cdnBlocked && !noCdnAlreadyInUrl && navigator.userAgent.indexOf("Googlebot") == -1) {
var noCdnAlreadyInUrl = window.location.href.indexOf('nocdn=true') != -1
if (cdnBlocked && !noCdnAlreadyInUrl && navigator.userAgent.indexOf('Googlebot') == -1) {
//- Set query param, server will not set CDN url
window.location.search += "&nocdn=true";
window.location.search += '&nocdn=true'
}
})

View File

@@ -7,7 +7,7 @@ block entrypointVar
- entrypoint = 'marketing'
block body
if (typeof suppressNavbar === "undefined")
if typeof suppressNavbar === 'undefined'
if bootstrapVersion === 5
include layout/navbar-marketing-bootstrap-5
else
@@ -15,7 +15,7 @@ block body
block content
if (typeof suppressFooter === "undefined")
if typeof suppressFooter === 'undefined'
if showThinFooter
if bootstrapVersion === 5
include layout/thin-footer-bootstrap-5
@@ -24,13 +24,13 @@ block body
else
include layout/fat-footer
if (typeof(suppressCookieBanner) == 'undefined')
if typeof suppressCookieBanner == 'undefined'
include _cookie_banner
if bootstrapVersion === 5
!= moduleIncludes("contactModal-marketing-bootstrap-5", locals)
!= moduleIncludes('contactModal-marketing-bootstrap-5', locals)
else
!= moduleIncludes("contactModal-marketing", locals)
!= moduleIncludes('contactModal-marketing', locals)
block prepend foot-scripts
+bootstrap-js(bootstrapVersion)

View File

@@ -7,10 +7,10 @@ include ./_mixins/bootstrap_js
block entrypointVar
- entrypoint = 'marketing'
block isApplicationPageVar
- isApplicationPage = true
block append meta
- const canDisplayAdminMenu = hasAdminAccess()
- const canDisplayAdminRedirect = canRedirectToAdminDomain()
@@ -22,44 +22,52 @@ block append meta
- const enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on')
- const showSignUpLink = hasFeature('registration-page')
meta(name="ol-navbar" data-type="json" content={
customLogo: settings.nav.custom_logo,
title: nav.title,
canDisplayAdminMenu,
canDisplayAdminRedirect,
canDisplaySplitTestMenu,
canDisplaySurveyMenu,
canDisplayScriptLogMenu,
enableUpgradeButton,
suppressNavbarRight: !!suppressNavbarRight,
suppressNavContentLinks: !!suppressNavContentLinks,
showSubscriptionLink: nav.showSubscriptionLink,
showSignUpLink: showSignUpLink,
currentUrl: currentUrl,
sessionUser: sessionUser ? { email: sessionUser.email} : undefined,
adminUrl: settings.adminUrl,
items: cloneAndTranslateText(nav.header_extras)
})
meta(name="ol-footer" data-type="json" content={
showThinFooter: showThinFooter,
showPoweredBy: !hasFeature('saas') && !settings.nav.hide_powered_by,
subdomainLang: settings.i18n.subdomainLang,
translatedLanguages: settings.translatedLanguages,
leftItems: cloneAndTranslateText(settings.nav.left_footer),
rightItems: settings.nav.right_footer
})
meta(
name='ol-navbar'
data-type='json'
content={
customLogo: settings.nav.custom_logo,
title: nav.title,
canDisplayAdminMenu,
canDisplayAdminRedirect,
canDisplaySplitTestMenu,
canDisplaySurveyMenu,
canDisplayScriptLogMenu,
enableUpgradeButton,
suppressNavbarRight: !!suppressNavbarRight,
suppressNavContentLinks: !!suppressNavContentLinks,
showSubscriptionLink: nav.showSubscriptionLink,
showSignUpLink: showSignUpLink,
currentUrl: currentUrl,
sessionUser: sessionUser ? {email: sessionUser.email} : undefined,
adminUrl: settings.adminUrl,
items: cloneAndTranslateText(nav.header_extras),
}
)
meta(
name='ol-footer'
data-type='json'
content={
showThinFooter: showThinFooter,
showPoweredBy: !hasFeature('saas') && !settings.nav.hide_powered_by,
subdomainLang: settings.i18n.subdomainLang,
translatedLanguages: settings.translatedLanguages,
leftItems: cloneAndTranslateText(settings.nav.left_footer),
rightItems: settings.nav.right_footer,
}
)
block body
if (typeof suppressNavbar === "undefined")
if typeof suppressNavbar === 'undefined'
include layout/navbar-marketing-react-bootstrap-5
block content
if (typeof suppressFooter === "undefined")
if typeof suppressFooter === 'undefined'
if showThinFooter
include layout/thin-footer-bootstrap-5
else
include layout/fat-footer-react-bootstrap-5
if (typeof suppressCookieBanner === "undefined")
if typeof suppressCookieBanner === 'undefined'
include _cookie_banner

View File

@@ -7,7 +7,7 @@ block entrypointVar
- entrypoint = 'marketing'
block body
if (typeof(suppressNavbar) == "undefined")
if typeof suppressNavbar == 'undefined'
if bootstrapVersion === 5
include layout/navbar-marketing-bootstrap-5
else
@@ -17,23 +17,23 @@ block body
//- 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 typeof suppressFooter == 'undefined'
if showThinFooter
if bootstrapVersion === 5
include layout/thin-footer-bootstrap-5
else
else
include layout/thin-footer
else
include layout/fat-footer-website-redesign
if (typeof(suppressCookieBanner) == 'undefined')
if typeof suppressCookieBanner == 'undefined'
include _cookie_banner
block contactModal
if bootstrapVersion === 5
!= moduleIncludes("contactModal-marketing-bootstrap-5", locals)
!= moduleIncludes('contactModal-marketing-bootstrap-5', locals)
else
!= moduleIncludes("contactModal-marketing", locals)
!= moduleIncludes('contactModal-marketing', locals)
block prepend foot-scripts
+bootstrap-js(bootstrapVersion)

View File

@@ -1,9 +1,9 @@
.fat-footer-base
.fat-footer-base-section.fat-footer-base-meta
.fat-footer-base-item
.fat-footer-base-item
.fat-footer-base-copyright © #{new Date().getFullYear()} Overleaf
a(href="/legal") #{translate('privacy_and_terms')}
a(href="https://www.digital-science.com/security-certifications/") #{translate('compliance')}
a(href='/legal') #{translate('privacy_and_terms')}
a(href='https://www.digital-science.com/security-certifications/') #{translate('compliance')}
ul.fat-footer-base-item.list-unstyled.fat-footer-base-language
if bootstrapVersion === 5
include language-picker-bootstrap-5
@@ -11,22 +11,53 @@
include language-picker
.fat-footer-base-section.fat-footer-base-social
.fat-footer-base-item
a.fat-footer-social.x-logo(href="https://x.com/overleaf")
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1227" height="25")
path(d="M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z")
a.fat-footer-social.x-logo(href='https://x.com/overleaf')
svg(
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 1200 1227'
height='25'
)
path(
d='M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z'
)
span.visually-hidden #{translate("app_on_x", {social: "X"})}
a.fat-footer-social.facebook-logo(href="https://www.facebook.com/overleaf.editor")
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 666.66668 666.66717" height="25")
a.fat-footer-social.facebook-logo(
href='https://www.facebook.com/overleaf.editor'
)
svg(
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 666.66668 666.66717'
height='25'
)
defs
clipPath(id="a" clipPathUnits="userSpaceOnUse")
path(d="M0 700h700V0H0Z")
g(clip-path="url(#a)" transform="matrix(1.33333 0 0 -1.33333 -133.333 800)")
path.background(d="M0 0c0 138.071-111.929 250-250 250S-500 138.071-500 0c0-117.245 80.715-215.622 189.606-242.638v166.242h-51.552V0h51.552v32.919c0 85.092 38.508 124.532 122.048 124.532 15.838 0 43.167-3.105 54.347-6.211V81.986c-5.901.621-16.149.932-28.882.932-40.993 0-56.832-15.528-56.832-55.9V0h81.659l-14.028-76.396h-67.631v-171.773C-95.927-233.218 0-127.818 0 0" fill="#0866ff" transform="translate(600 350)")
path.text(d="m0 0 14.029 76.396H-67.63v27.019c0 40.372 15.838 55.899 56.831 55.899 12.733 0 22.981-.31 28.882-.931v69.253c-11.18 3.106-38.509 6.212-54.347 6.212-83.539 0-122.048-39.441-122.048-124.533V76.396h-51.552V0h51.552v-166.242a250.559 250.559 0 0 1 60.394-7.362c10.254 0 20.358.632 30.288 1.831V0Z" fill="#fff" transform="translate(447.918 273.604)")
clipPath(id='a' clipPathUnits='userSpaceOnUse')
path(d='M0 700h700V0H0Z')
g(
clip-path='url(#a)'
transform='matrix(1.33333 0 0 -1.33333 -133.333 800)'
)
path.background(
d='M0 0c0 138.071-111.929 250-250 250S-500 138.071-500 0c0-117.245 80.715-215.622 189.606-242.638v166.242h-51.552V0h51.552v32.919c0 85.092 38.508 124.532 122.048 124.532 15.838 0 43.167-3.105 54.347-6.211V81.986c-5.901.621-16.149.932-28.882.932-40.993 0-56.832-15.528-56.832-55.9V0h81.659l-14.028-76.396h-67.631v-171.773C-95.927-233.218 0-127.818 0 0'
fill='#0866ff'
transform='translate(600 350)'
)
path.text(
d='m0 0 14.029 76.396H-67.63v27.019c0 40.372 15.838 55.899 56.831 55.899 12.733 0 22.981-.31 28.882-.931v69.253c-11.18 3.106-38.509 6.212-54.347 6.212-83.539 0-122.048-39.441-122.048-124.533V76.396h-51.552V0h51.552v-166.242a250.559 250.559 0 0 1 60.394-7.362c10.254 0 20.358.632 30.288 1.831V0Z'
fill='#fff'
transform='translate(447.918 273.604)'
)
span.visually-hidden #{translate("app_on_x", {social: "Facebook"})}
a.fat-footer-social.linkedin-logo(href="https://www.linkedin.com/company/writelatex-limited")
svg(xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72" height="25")
g(fill="none" fill-rule="evenodd")
path.background(fill="#0B66C3" d="M8 72h56a8 8 0 0 0 8-8V8a8 8 0 0 0-8-8H8a8 8 0 0 0-8 8v56a8 8 0 0 0 8 8")
path.text(fill="#FFF" d="M62 62H51.316V43.802c0-4.99-1.896-7.777-5.845-7.777-4.296 0-6.54 2.901-6.54 7.777V62H28.632V27.333H38.93v4.67s3.096-5.729 10.453-5.729c7.353 0 12.617 4.49 12.617 13.777zM16.35 22.794c-3.508 0-6.35-2.864-6.35-6.397C10 12.864 12.842 10 16.35 10c3.507 0 6.347 2.864 6.347 6.397 0 3.533-2.84 6.397-6.348 6.397ZM11.032 62h10.736V27.333H11.033V62")
a.fat-footer-social.linkedin-logo(
href='https://www.linkedin.com/company/writelatex-limited'
)
svg(xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 72' height='25')
g(fill='none' fill-rule='evenodd')
path.background(
fill='#0B66C3'
d='M8 72h56a8 8 0 0 0 8-8V8a8 8 0 0 0-8-8H8a8 8 0 0 0-8 8v56a8 8 0 0 0 8 8'
)
path.text(
fill='#FFF'
d='M62 62H51.316V43.802c0-4.99-1.896-7.777-5.845-7.777-4.296 0-6.54 2.901-6.54 7.777V62H28.632V27.333H38.93v4.67s3.096-5.729 10.453-5.729c7.353 0 12.617 4.49 12.617 13.777zM16.35 22.794c-3.508 0-6.35-2.864-6.35-6.397C10 12.864 12.842 10 16.35 10c3.507 0 6.347 2.864 6.347 6.397 0 3.533-2.84 6.397-6.348 6.397ZM11.032 62h10.736V27.333H11.033V62'
)
span.visually-hidden #{translate("app_on_x", {social: "LinkedIn"})}

View File

@@ -1,84 +1,87 @@
footer.fat-footer.hidden-print.website-redesign-fat-footer
.fat-footer-container(role="navigation" aria-label=translate('footer_navigation'))
.fat-footer-container(
role='navigation'
aria-label=translate('footer_navigation')
)
.fat-footer-sections(class=hideFatFooter ? 'hidden' : undefined)
.footer-section#footer-brand
a(href='/', aria-label=settings.appName).footer-brand
#footer-brand.footer-section
a.footer-brand(href='/' aria-label=settings.appName)
.footer-section
h2.footer-section-heading #{translate('About')}
ul.list-unstyled
li
a(href="/about") #{translate('footer_about_us')}
a(href='/about') #{translate('footer_about_us')}
li
a(href="/about/values") #{translate('our_values')}
a(href='/about/values') #{translate('our_values')}
li
a(href="https://digitalscience.pinpointhq.com/") #{translate('careers')}
a(href='https://digitalscience.pinpointhq.com/') #{translate('careers')}
li
a(href="/for/press") !{translate('press_and_awards')}
a(href='/for/press') !{translate('press_and_awards')}
li
a(href="/blog") #{translate('blog')}
a(href='/blog') #{translate('blog')}
.footer-section
h2.footer-section-heading #{translate('learn')}
ul.list-unstyled
li
a(href="/learn/latex/Learn_LaTeX_in_30_minutes") #{translate('latex_in_thirty_minutes')}
a(href='/learn/latex/Learn_LaTeX_in_30_minutes') #{translate('latex_in_thirty_minutes')}
li
a(href="/latex/templates") #{translate('templates')}
a(href='/latex/templates') #{translate('templates')}
li
a(href="/events/webinars") #{translate('webinars')}
a(href='/events/webinars') #{translate('webinars')}
li
a(href="/learn/latex/Tutorials") #{translate('tutorials')}
a(href='/learn/latex/Tutorials') #{translate('tutorials')}
li
a(href="/learn/latex/Inserting_Images") #{translate('how_to_insert_images')}
a(href='/learn/latex/Inserting_Images') #{translate('how_to_insert_images')}
li
a(href="/learn/latex/Tables") #{translate('how_to_create_tables')}
a(href='/learn/latex/Tables') #{translate('how_to_create_tables')}
.footer-section
h2.footer-section-heading !{translate('footer_plans_and_pricing')}
ul.list-unstyled
li
a(href="/learn/how-to/Overleaf_premium_features") #{translate('premium_features')}
a(href='/learn/how-to/Overleaf_premium_features') #{translate('premium_features')}
li
a(href="/user/subscription/plans?itm_referrer=footer-for-indv-groups") !{translate('for_individuals_and_groups')}
a(href='/user/subscription/plans?itm_referrer=footer-for-indv-groups') !{translate('for_individuals_and_groups')}
li
a(href="/for/enterprises") #{translate('for_business')}
a(href='/for/enterprises') #{translate('for_business')}
li
a(href="/for/universities") #{translate('for_universities')}
a(href='/for/universities') #{translate('for_universities')}
li
a(
data-ol-for-students-link
href="/user/subscription/plans?itm_referrer=footer-for-students#student-annual"
href='/user/subscription/plans?itm_referrer=footer-for-students#student-annual'
) #{translate('for_students')}
li
a(href="/for/government") #{translate('for_government')}
a(href='/for/government') #{translate('for_government')}
.footer-section
h2.footer-section-heading #{translate('get_involved')}
ul.list-unstyled
li
a(href="/for/community/advisors") #{translate('become_an_advisor')}
a(href='/for/community/advisors') #{translate('become_an_advisor')}
li
a(href="https://forms.gle/67PSpN1bLnjGCmPQ9") #{translate('let_us_know_what_you_think')}
a(href='https://forms.gle/67PSpN1bLnjGCmPQ9') #{translate('let_us_know_what_you_think')}
if user
li
a(href="/beta/participate") #{translate('join_beta_program')}
a(href='/beta/participate') #{translate('join_beta_program')}
.footer-section
h2.footer-section-heading #{translate('help')}
ul.list-unstyled
li
a(href="/about/why-latex") #{translate('why_latex')}
a(href='/about/why-latex') #{translate('why_latex')}
li
a(href="/learn") #{translate('Documentation')}
a(href='/learn') #{translate('Documentation')}
li
a(href="/contact") #{translate('footer_contact_us')}
a(href='/contact') #{translate('footer_contact_us')}
li
a(href="https://status.overleaf.com/") #{translate('website_status')}
a(href='https://status.overleaf.com/') #{translate('website_status')}
include fat-footer-base

View File

@@ -1,84 +1,87 @@
footer.fat-footer.hidden-print
.fat-footer-container(role="navigation" aria-label=translate('footer_navigation'))
.fat-footer-container(
role='navigation'
aria-label=translate('footer_navigation')
)
.fat-footer-sections(class=hideFatFooter ? 'hidden' : undefined)
.footer-section#footer-brand
a(href='/', aria-label=settings.appName).footer-brand
#footer-brand.footer-section
a.footer-brand(href='/' aria-label=settings.appName)
.footer-section
h2.footer-section-heading #{translate('About')}
ul.list-unstyled
li
a(href="/about") #{translate('footer_about_us')}
a(href='/about') #{translate('footer_about_us')}
li
a(href="/about/values") #{translate('our_values')}
a(href='/about/values') #{translate('our_values')}
li
a(href="https://digitalscience.pinpointhq.com/") #{translate('careers')}
a(href='https://digitalscience.pinpointhq.com/') #{translate('careers')}
li
a(href="/for/press") !{translate('press_and_awards')}
a(href='/for/press') !{translate('press_and_awards')}
li
a(href="/blog") #{translate('blog')}
a(href='/blog') #{translate('blog')}
.footer-section
h2.footer-section-heading #{translate('learn')}
ul.list-unstyled
li
a(href="/learn/latex/Learn_LaTeX_in_30_minutes") #{translate('latex_in_thirty_minutes')}
a(href='/learn/latex/Learn_LaTeX_in_30_minutes') #{translate('latex_in_thirty_minutes')}
li
a(href="/latex/templates") #{translate('templates')}
a(href='/latex/templates') #{translate('templates')}
li
a(href="/events/webinars") #{translate('webinars')}
a(href='/events/webinars') #{translate('webinars')}
li
a(href="/learn/latex/Tutorials") #{translate('tutorials')}
a(href='/learn/latex/Tutorials') #{translate('tutorials')}
li
a(href="/learn/latex/Inserting_Images") #{translate('how_to_insert_images')}
a(href='/learn/latex/Inserting_Images') #{translate('how_to_insert_images')}
li
a(href="/learn/latex/Tables") #{translate('how_to_create_tables')}
a(href='/learn/latex/Tables') #{translate('how_to_create_tables')}
.footer-section
h2.footer-section-heading !{translate('footer_plans_and_pricing')}
ul.list-unstyled
li
a(href="/learn/how-to/Overleaf_premium_features") #{translate('premium_features')}
a(href='/learn/how-to/Overleaf_premium_features') #{translate('premium_features')}
li
a(href="/user/subscription/plans?itm_referrer=footer-for-indv-groups") !{translate('for_individuals_and_groups')}
a(href='/user/subscription/plans?itm_referrer=footer-for-indv-groups') !{translate('for_individuals_and_groups')}
li
a(href="/for/enterprises") #{translate('for_enterprise')}
a(href='/for/enterprises') #{translate('for_enterprise')}
li
a(href="/for/universities") #{translate('for_universities')}
a(href='/for/universities') #{translate('for_universities')}
li
a(
data-ol-for-students-link
href="/user/subscription/plans?itm_referrer=footer-for-students#student-annual"
href='/user/subscription/plans?itm_referrer=footer-for-students#student-annual'
) #{translate('for_students')}
li
a(href="/for/government") #{translate('for_government')}
a(href='/for/government') #{translate('for_government')}
.footer-section
h2.footer-section-heading #{translate('get_involved')}
ul.list-unstyled
li
a(href="/for/community/advisors") #{translate('become_an_advisor')}
a(href='/for/community/advisors') #{translate('become_an_advisor')}
li
a(href="https://forms.gle/67PSpN1bLnjGCmPQ9") #{translate('let_us_know_what_you_think')}
a(href='https://forms.gle/67PSpN1bLnjGCmPQ9') #{translate('let_us_know_what_you_think')}
if user
li
a(href="/beta/participate") #{translate('join_beta_program')}
a(href='/beta/participate') #{translate('join_beta_program')}
.footer-section
h2.footer-section-heading #{translate('help')}
ul.list-unstyled
li
a(href="/about/why-latex") #{translate('why_latex')}
a(href='/about/why-latex') #{translate('why_latex')}
li
a(href="/learn") #{translate('Documentation')}
a(href='/learn') #{translate('Documentation')}
li
a(href="/contact") #{translate('footer_contact_us')}
a(href='/contact') #{translate('footer_contact_us')}
li
a(href="https://status.overleaf.com/") #{translate('website_status')}
a(href='https://status.overleaf.com/') #{translate('website_status')}
include fat-footer-base

View File

@@ -1,27 +1,35 @@
include ../_mixins/material_symbol
li.dropdown.dropup.subdued(dropdown).language-picker
li.dropdown.dropup.subdued.language-picker(dropdown)
button#language-picker-toggle.btn.btn-link.btn-inline-link(
dropdown-toggle,
data-ol-lang-selector-tooltip,
data-bs-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false",
aria-label="Select " + translate('language'),
dropdown-toggle
data-ol-lang-selector-tooltip
data-bs-toggle='dropdown'
aria-haspopup='true'
aria-expanded='false'
aria-label='Select ' + translate('language')
tooltip=translate('language')
title=translate('language')
)
+material-symbol("translate")
+material-symbol('translate')
| &nbsp;
span.language-picker-text #{settings.translatedLanguages[currentLngCode]}
ul.dropdown-menu.dropdown-menu-sm-width(role="menu" aria-labelledby="language-picker-toggle")
ul.dropdown-menu.dropdown-menu-sm-width(
role='menu'
aria-labelledby='language-picker-toggle'
)
li.dropdown-header #{translate("language")}
each subdomainDetails, subdomain in settings.i18n.subdomainLang
if !subdomainDetails.hide
- let isActive = subdomainDetails.lngCode === currentLngCode
li.lng-option
a.menu-indent(href=subdomainDetails.url+currentUrlWithQueryParams, role="menuitem", class=isActive ? 'dropdown-item active' : 'dropdown-item', aria-selected=isActive ? 'true' : 'false')
a.menu-indent(
href=subdomainDetails.url + currentUrlWithQueryParams
role='menuitem'
class=isActive ? 'dropdown-item active' : 'dropdown-item'
aria-selected=isActive ? 'true' : 'false'
)
| #{settings.translatedLanguages[subdomainDetails.lngCode]}
if subdomainDetails.lngCode === currentLngCode
+material-symbol("check", "dropdown-item-trailing-icon")
+material-symbol('check', 'dropdown-item-trailing-icon')

View File

@@ -1,13 +1,13 @@
li.dropdown.dropup.subdued(dropdown).language-picker
a.dropdown-toggle#language-picker-toggle(
href="#",
dropdown-toggle,
data-ol-lang-selector-tooltip,
data-toggle="dropdown",
role="button"
aria-haspopup="true",
aria-expanded="false",
aria-label="Select " + translate('language'),
li.dropdown.dropup.subdued.language-picker(dropdown)
a#language-picker-toggle.dropdown-toggle(
href='#'
dropdown-toggle
data-ol-lang-selector-tooltip
data-toggle='dropdown'
role='button'
aria-haspopup='true'
aria-expanded='false'
aria-label='Select ' + translate('language')
tooltip=translate('language')
title=translate('language')
)
@@ -15,10 +15,13 @@ li.dropdown.dropup.subdued(dropdown).language-picker
|
| #{settings.translatedLanguages[currentLngCode]}
ul.dropdown-menu(role="menu" aria-labelledby="language-picker-toggle")
ul.dropdown-menu(role='menu' aria-labelledby='language-picker-toggle')
li.dropdown-header #{translate("language")}
each subdomainDetails, subdomain in settings.i18n.subdomainLang
if !subdomainDetails.hide
li.lng-option
a.menu-indent(href=subdomainDetails.url+currentUrlWithQueryParams role="menuitem")
a.menu-indent(
href=subdomainDetails.url + currentUrlWithQueryParams
role='menuitem'
)
| #{settings.translatedLanguages[subdomainDetails.lngCode]}

View File

@@ -1,18 +1,20 @@
doctype html
html(lang="en")
html(lang='en')
- metadata = metadata || {}
block vars
head
if (metadata && metadata.title)
if metadata && metadata.title
title= metadata.title
if metadata && metadata.viewport
meta(name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes")
meta(
name='viewport'
content='width=device-width, initial-scale=1.0, user-scalable=yes'
)
link(rel="icon", href="/favicon.ico")
link(rel='icon' href='/favicon.ico')
if buildCssPath
link(rel="stylesheet", href=buildCssPath('', 5))
link(rel='stylesheet' href=buildCssPath('', 5))
block body

View File

@@ -1,26 +1,32 @@
include ../_mixins/navbar
nav.navbar.navbar-default.navbar-main.navbar-expand-lg(class={
'website-redesign-navbar': isWebsiteRedesign
})
nav.navbar.navbar-default.navbar-main.navbar-expand-lg(
class={
'website-redesign-navbar': isWebsiteRedesign,
}
)
.container-fluid.navbar-container
.navbar-header
if settings.nav.custom_logo
a(href='/', aria-label=settings.appName, style='background-image:url("'+settings.nav.custom_logo+'")').navbar-brand
else if (nav.title)
a(href='/', aria-label=settings.appName).navbar-title #{nav.title}
a.navbar-brand(
href='/'
aria-label=settings.appName
style='background-image:url("' + settings.nav.custom_logo + '")'
)
else if nav.title
a.navbar-title(href='/' aria-label=settings.appName) #{nav.title}
else
a(href='/', aria-label=settings.appName).navbar-brand
a.navbar-brand(href='/' aria-label=settings.appName)
- var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on')
if (enableUpgradeButton)
if enableUpgradeButton
a.btn.btn-primary.me-2.d-md-none(
href="/user/subscription/plans"
event-tracking="upgrade-button-click"
event-tracking-mb="true"
event-tracking-label="upgrade"
event-tracking-trigger="click"
event-segmentation='{"source": "dashboard-top", "project-dashboard-react": "enabled", "is-dashboard-sidebar-hidden": "true", "is-screen-width-less-than-768px": "true"}'
href='/user/subscription/plans'
event-tracking='upgrade-button-click'
event-tracking-mb='true'
event-tracking-label='upgrade'
event-tracking-trigger='click'
event-segmentation={source: 'dashboard-top', projectDashboardReact: 'enabled', isDashboardSidebarHidden: 'true', isScreenWidthLessThan768px: 'true'}
) #{translate("upgrade")}
- var canDisplayAdminMenu = hasAdminAccess()
@@ -29,45 +35,45 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg(class={
- var canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu
- var canDisplayScriptLogMenu = hasFeature('saas') && canDisplayAdminMenu
if (typeof suppressNavbarRight === "undefined")
if typeof suppressNavbarRight === 'undefined'
button.navbar-toggler.collapsed(
type="button",
data-bs-toggle="collapse",
data-bs-target="#navbar-main-collapse"
aria-controls="navbar-main-collapse"
aria-expanded="false"
aria-label="Toggle " + translate('navigation')
type='button'
data-bs-toggle='collapse'
data-bs-target='#navbar-main-collapse'
aria-controls='navbar-main-collapse'
aria-expanded='false'
aria-label='Toggle ' + translate('navigation')
)
i.fa.fa-bars(aria-hidden="true")
i.fa.fa-bars(aria-hidden='true')
.navbar-collapse.collapse#navbar-main-collapse
ul.nav.navbar-nav.navbar-right.ms-auto(role="menubar")
if (canDisplayAdminMenu || canDisplayAdminRedirect || canDisplaySplitTestMenu)
#navbar-main-collapse.navbar-collapse.collapse
ul.nav.navbar-nav.navbar-right.ms-auto(role='menubar')
if canDisplayAdminMenu || canDisplayAdminRedirect || canDisplaySplitTestMenu
+nav-item.dropdown.subdued
button.dropdown-toggle(
aria-haspopup="true",
aria-expanded="false",
data-bs-toggle="dropdown"
role="menuitem"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": "admin", "location": "top-menu"}
aria-haspopup='true'
aria-expanded='false'
data-bs-toggle='dropdown'
role='menuitem'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'admin', location: 'top-menu'}
)
| Admin
+dropdown-menu.dropdown-menu-end
if canDisplayAdminMenu
+dropdown-menu-link-item()(href="/admin") Manage Site
+dropdown-menu-link-item()(href="/admin/user") Manage Users
+dropdown-menu-link-item()(href="/admin/project") Project URL Lookup
+dropdown-menu-link-item(href='/admin') Manage Site
+dropdown-menu-link-item(href='/admin/user') Manage Users
+dropdown-menu-link-item(href='/admin/project') Project URL Lookup
if canDisplayAdminRedirect
+dropdown-menu-link-item()(href=settings.adminUrl) Switch to Admin
+dropdown-menu-link-item(href=settings.adminUrl) Switch to Admin
if canDisplaySplitTestMenu
+dropdown-menu-link-item()(href="/admin/split-test") Manage Feature Flags
+dropdown-menu-link-item(href='/admin/split-test') Manage Feature Flags
if canDisplaySurveyMenu
+dropdown-menu-link-item()(href="/admin/survey") Manage Surveys
+dropdown-menu-link-item(href='/admin/survey') Manage Surveys
if canDisplayScriptLogMenu
+dropdown-menu-link-item()(href="/admin/script-logs") View Script Logs
+dropdown-menu-link-item(href='/admin/script-logs') View Script Logs
// loop over header_extras
each item in nav.header_extras
@@ -86,14 +92,14 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg(class={
if item.dropdown
+nav-item.dropdown(class=item.class)
button.dropdown-toggle(
aria-haspopup="true",
aria-expanded="false",
data-bs-toggle="dropdown"
role="menuitem"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": item.trackingKey, "location": "top-menu"}
aria-haspopup='true'
aria-expanded='false'
data-bs-toggle='dropdown'
role='menuitem'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: item.trackingKey, location: 'top-menu'}
)
| !{translate(item.text)}
+dropdown-menu.dropdown-menu-end
@@ -101,31 +107,41 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg(class={
if child.divider
+dropdown-menu-divider
else if child.isContactUs
+dropdown-menu-link-item()(data-ol-open-contact-form-modal="contact-us" data-bs-target="#contactUsModal" href data-bs-toggle="modal" event-tracking="menu-click" event-tracking-mb="true" event-tracking-trigger="click" event-segmentation={"item": "contact", "location": "top-menu"})
+dropdown-menu-link-item(
data-ol-open-contact-form-modal='contact-us'
data-bs-target='#contactUsModal'
href
data-bs-toggle='modal'
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'contact', location: 'top-menu'}
)
span
| #{translate("contact_us")}
else
if child.url
+dropdown-menu-link-item()(
href=child.url,
class=child.class,
event-tracking="menu-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ item: child.trackingKey, location: 'top-menu' }
+dropdown-menu-link-item(
href=child.url
class=child.class
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: child.trackingKey, location: 'top-menu'}
) !{translate(child.text)}
else
+dropdown-menu-item !{translate(child.text)}
+dropdown-menu-item
| !{translate(child.text)}
else
+nav-item(class=item.class)
if item.url
+nav-link(
href=item.url,
class=item.class,
event-tracking="menu-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ item: item.trackingKey, location: 'top-menu' }
href=item.url
class=item.class
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: item.trackingKey, location: 'top-menu'}
) !{translate(item.text)}
else
| !{translate(item.text)}
@@ -136,48 +152,48 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg(class={
if hasFeature('registration-page')
+nav-item.primary
+nav-link(
href="/register"
event-tracking="menu-click"
event-tracking-action="clicked"
event-tracking-trigger="click"
event-tracking-mb="true"
event-segmentation={ page: currentUrl, item: 'register', location: 'top-menu' }
href='/register'
event-tracking='menu-click'
event-tracking-action='clicked'
event-tracking-trigger='click'
event-tracking-mb='true'
event-segmentation={page: currentUrl, item: 'register', location: 'top-menu'}
) #{translate('sign_up')}
// login link
+nav-item
+nav-link(
href="/login"
event-tracking="menu-click"
event-tracking-action="clicked"
event-tracking-trigger="click"
event-tracking-mb="true"
event-segmentation={ page: currentUrl, item: 'login', location: 'top-menu' }
href='/login'
event-tracking='menu-click'
event-tracking-action='clicked'
event-tracking-trigger='click'
event-tracking-mb='true'
event-segmentation={page: currentUrl, item: 'login', location: 'top-menu'}
) #{translate('log_in')}
// projects link and account menu
if getSessionUser()
+nav-item
+nav-link(href="/project") #{translate('Projects')}
+nav-link(href='/project') #{translate('Projects')}
+nav-item.dropdown
button.dropdown-toggle(
aria-haspopup="true",
aria-expanded="false",
data-bs-toggle="dropdown"
role="menuitem"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": "account", "location": "top-menu"}
aria-haspopup='true'
aria-expanded='false'
data-bs-toggle='dropdown'
role='menuitem'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'account', location: 'top-menu'}
)
| #{translate('Account')}
+dropdown-menu.dropdown-menu-end
+dropdown-menu-item
div.disabled.dropdown-item #{getSessionUser().email}
.disabled.dropdown-item #{getSessionUser().email}
+dropdown-menu-divider
+dropdown-menu-link-item()(href="/user/settings") #{translate('account_settings')}
+dropdown-menu-link-item(href='/user/settings') #{translate('account_settings')}
if nav.showSubscriptionLink
+dropdown-menu-link-item()(href="/user/subscription") #{translate('subscription')}
+dropdown-menu-link-item(href='/user/subscription') #{translate('subscription')}
+dropdown-menu-divider
+dropdown-menu-item
//-
@@ -185,14 +201,10 @@ nav.navbar.navbar-default.navbar-main.navbar-expand-lg(class={
this is that if the button is inside the form, screen readers will not count it in the total
number of menu items.
button.btn-link.text-left.dropdown-menu-button.dropdown-item(
role="menuitem",
tabindex="-1"
form="logOutForm"
role='menuitem'
tabindex='-1'
form='logOutForm'
)
| #{translate('log_out')}
form(
method="POST",
action="/logout",
id="logOutForm"
)
input(name='_csrf', type='hidden', value=csrfToken)
form(method='POST' action='/logout' id='logOutForm')
input(name='_csrf' type='hidden' value=csrfToken)

View File

@@ -1,32 +1,44 @@
nav.navbar.navbar-default.navbar-main(class={
'website-redesign-navbar': isWebsiteRedesign
})
nav.navbar.navbar-default.navbar-main(
class={
'website-redesign-navbar': isWebsiteRedesign,
}
)
.container-fluid
.navbar-header
if (typeof(suppressNavbarRight) == "undefined")
if typeof suppressNavbarRight == 'undefined'
button.navbar-toggle.collapsed(
type="button",
data-toggle="collapse",
data-target="#navbar-main-collapse"
aria-label="Toggle " + translate('navigation')
type='button'
data-toggle='collapse'
data-target='#navbar-main-collapse'
aria-label='Toggle ' + translate('navigation')
)
i.fa.fa-bars(aria-hidden="true")
i.fa.fa-bars(aria-hidden='true')
- var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on')
if (enableUpgradeButton)
if enableUpgradeButton
//- prettier-ignore
a.btn.btn-primary.pull-right.me-2.visible-xs(
href="/user/subscription/plans"
event-tracking="upgrade-button-click"
event-tracking-mb="true"
event-tracking-label="upgrade"
event-tracking-trigger="click"
event-segmentation='{"source": "dashboard-top", "project-dashboard-react": "enabled", "is-dashboard-sidebar-hidden": "true", "is-screen-width-less-than-768px": "true"}'
href='/user/subscription/plans'
event-tracking='upgrade-button-click'
event-tracking-mb='true'
event-tracking-label='upgrade'
event-tracking-trigger='click'
event-segmentation={
source: "dashboard-top",
"project-dashboard-react": "enabled",
"is-dashboard-sidebar-hidden": "true",
"is-screen-width-less-than-768px": "true"
}
) #{translate("upgrade")}
if settings.nav.custom_logo
a(href='/', aria-label=settings.appName, style='background-image:url("'+settings.nav.custom_logo+'")').navbar-brand
else if (nav.title)
a(href='/', aria-label=settings.appName).navbar-title #{nav.title}
a.navbar-brand(
href='/'
aria-label=settings.appName
style='background-image:url("' + settings.nav.custom_logo + '")'
)
else if nav.title
a.navbar-title(href='/' aria-label=settings.appName) #{nav.title}
else
a(href='/', aria-label=settings.appName).navbar-brand
a.navbar-brand(href='/' aria-label=settings.appName)
- var canDisplayAdminMenu = hasAdminAccess()
- var canDisplayAdminRedirect = canRedirectToAdminDomain()
@@ -34,44 +46,44 @@ nav.navbar.navbar-default.navbar-main(class={
- var canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu
- var canDisplayScriptLogMenu = hasFeature('saas') && canDisplayAdminMenu
if (typeof(suppressNavbarRight) == "undefined")
.navbar-collapse.collapse#navbar-main-collapse
if typeof suppressNavbarRight == 'undefined'
#navbar-main-collapse.navbar-collapse.collapse
ul.nav.navbar-nav.navbar-right
if (canDisplayAdminMenu || canDisplayAdminRedirect || canDisplaySplitTestMenu)
if canDisplayAdminMenu || canDisplayAdminRedirect || canDisplaySplitTestMenu
li.dropdown.subdued
a.dropdown-toggle(
href="#",
role="button",
aria-haspopup="true",
aria-expanded="false",
data-toggle="dropdown"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": "admin", "location": "top-menu"}
href='#'
role='button'
aria-haspopup='true'
aria-expanded='false'
data-toggle='dropdown'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'admin', location: 'top-menu'}
)
| Admin
span.caret
ul.dropdown-menu
if canDisplayAdminMenu
li
a(href="/admin") Manage Site
a(href='/admin') Manage Site
li
a(href="/admin/user") Manage Users
a(href='/admin/user') Manage Users
li
a(href="/admin/project") Project URL Lookup
a(href='/admin/project') Project URL Lookup
if canDisplayAdminRedirect
li
a(href=settings.adminUrl) Switch to Admin
if canDisplaySplitTestMenu
li
a(href="/admin/split-test") Manage Feature Flags
a(href='/admin/split-test') Manage Feature Flags
if canDisplaySurveyMenu
li
a(href="/admin/survey") Manage Surveys
a(href='/admin/survey') Manage Surveys
if canDisplayScriptLogMenu
li
a(href="/admin/script-logs") View Script Logs
a(href='/admin/script-logs') View Script Logs
// loop over header_extras
each item in nav.header_extras
@@ -90,15 +102,15 @@ nav.navbar.navbar-default.navbar-main(class={
if item.dropdown
li.dropdown(class=item.class)
a.dropdown-toggle(
href="#",
role="button",
aria-haspopup="true",
aria-expanded="false",
data-toggle="dropdown"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": item.trackingKey, "location": "top-menu"}
href='#'
role='button'
aria-haspopup='true'
aria-expanded='false'
data-toggle='dropdown'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: item.trackingKey, location: 'top-menu'}
)
| !{translate(item.text)}
span.caret
@@ -108,18 +120,25 @@ nav.navbar.navbar-default.navbar-main(class={
li.divider
else if child.isContactUs
li
a(data-ol-open-contact-form-modal="contact-us" href event-tracking="menu-click" event-tracking-mb="true" event-tracking-trigger="click" event-segmentation={"item": "contact", "location": "top-menu"})
a(
data-ol-open-contact-form-modal='contact-us'
href
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'contact', location: 'top-menu'}
)
span
| #{translate("contact_us")}
else
li
if child.url
a(
href=child.url,
class=child.class,
event-tracking="menu-click"
event-tracking-mb="true"
event-tracking-trigger="click"
href=child.url
class=child.class
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: item.trackingKey, location: 'top-menu'}
) !{translate(child.text)}
else
@@ -128,12 +147,12 @@ nav.navbar.navbar-default.navbar-main(class={
li(class=item.class)
if item.url
a(
href=item.url,
class=item.class,
event-tracking="menu-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ item: item.trackingKey, location: 'top-menu' }
href=item.url
class=item.class
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: item.trackingKey, location: 'top-menu'}
) !{translate(item.text)}
else
| !{translate(item.text)}
@@ -144,54 +163,54 @@ nav.navbar.navbar-default.navbar-main(class={
if hasFeature('registration-page')
li.primary
a(
href="/register"
event-tracking="menu-click"
event-tracking-action="clicked"
event-tracking-trigger="click"
event-tracking-mb="true"
event-segmentation={ page: currentUrl, item: 'register', location: 'top-menu' }
href='/register'
event-tracking='menu-click'
event-tracking-action='clicked'
event-tracking-trigger='click'
event-tracking-mb='true'
event-segmentation={page: currentUrl, item: 'register', location: 'top-menu'}
) #{translate('sign_up')}
// login link
li
a(
href="/login"
event-tracking="menu-click"
event-tracking-action="clicked"
event-tracking-trigger="click"
event-tracking-mb="true"
event-segmentation={ page: currentUrl, item: 'login', location: 'top-menu' }
href='/login'
event-tracking='menu-click'
event-tracking-action='clicked'
event-tracking-trigger='click'
event-tracking-mb='true'
event-segmentation={page: currentUrl, item: 'login', location: 'top-menu'}
) #{translate('log_in')}
// projects link and account menu
if getSessionUser()
li
a(href="/project") #{translate('Projects')}
a(href='/project') #{translate('Projects')}
li.dropdown
a.dropdown-toggle(
href="#",
role="button",
aria-haspopup="true",
aria-expanded="false",
data-toggle="dropdown"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": "account", "location": "top-menu"}
href='#'
role='button'
aria-haspopup='true'
aria-expanded='false'
data-toggle='dropdown'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'account', location: 'top-menu'}
)
| #{translate('Account')}
span.caret
ul.dropdown-menu
li
div.subdued #{getSessionUser().email}
.subdued #{getSessionUser().email}
li.divider.hidden-xs.hidden-sm
li
a(href="/user/settings") #{translate('account_settings')}
a(href='/user/settings') #{translate('account_settings')}
if nav.showSubscriptionLink
li
a(href="/user/subscription") #{translate('subscription')}
a(href='/user/subscription') #{translate('subscription')}
li.divider.hidden-xs.hidden-sm
li
form(method="POST" action="/logout")
input(name='_csrf', type='hidden', value=csrfToken)
form(method='POST' action='/logout')
input(name='_csrf' type='hidden' value=csrfToken)
button.btn-link.text-left.dropdown-menu-button #{translate('log_out')}

View File

@@ -1,30 +1,39 @@
nav.navbar.navbar-default.navbar-main.website-redesign-navbar
.container-fluid
.navbar-header
if (typeof(suppressNavbarRight) == "undefined")
if typeof suppressNavbarRight == 'undefined'
button.navbar-toggle.collapsed(
type="button",
data-toggle="collapse",
data-target="#navbar-main-collapse"
aria-label="Toggle " + translate('navigation')
type='button'
data-toggle='collapse'
data-target='#navbar-main-collapse'
aria-label='Toggle ' + translate('navigation')
)
i.fa.fa-bars(aria-hidden="true")
i.fa.fa-bars(aria-hidden='true')
- var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on')
if (enableUpgradeButton)
if enableUpgradeButton
a.btn.btn-primary.pull-right.me-2.visible-xs(
href="/user/subscription/plans"
event-tracking="upgrade-button-click"
event-tracking-mb="true"
event-tracking-label="upgrade"
event-tracking-trigger="click"
event-segmentation='{"source": "dashboard-top", "project-dashboard-react": "enabled", "is-dashboard-sidebar-hidden": "true", "is-screen-width-less-than-768px": "true"}'
href='/user/subscription/plans'
event-tracking='upgrade-button-click'
event-tracking-mb='true'
event-tracking-label='upgrade'
event-tracking-trigger='click'
event-segmentation={
source: 'dashboard-top',
projectDashboardReact: 'enabled',
isDashboardSidebarHidden: 'true',
isScreenWidthLessThan768px: 'true',
}
) #{translate("upgrade")}
if settings.nav.custom_logo
a(href='/', aria-label=settings.appName, style='background-image:url("'+settings.nav.custom_logo+'")').navbar-brand
else if (nav.title)
a(href='/', aria-label=settings.appName).navbar-title #{nav.title}
a.navbar-brand(
href='/'
aria-label=settings.appName
style='background-image:url("' + settings.nav.custom_logo + '")'
)
else if nav.title
a.navbar-title(href='/' aria-label=settings.appName) #{nav.title}
else
a(href='/', aria-label=settings.appName).navbar-brand
a.navbar-brand(href='/' aria-label=settings.appName)
- var canDisplayAdminMenu = hasAdminAccess()
- var canDisplayAdminRedirect = canRedirectToAdminDomain()
@@ -32,44 +41,44 @@ nav.navbar.navbar-default.navbar-main.website-redesign-navbar
- var canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu
- var canDisplayScriptLogMenu = hasFeature('saas') && canDisplayAdminMenu
if (typeof(suppressNavbarRight) == "undefined")
.navbar-collapse.collapse#navbar-main-collapse
if typeof suppressNavbarRight == 'undefined'
#navbar-main-collapse.navbar-collapse.collapse
ul.nav.navbar-nav.navbar-right
if (canDisplayAdminMenu || canDisplayAdminRedirect || canDisplaySplitTestMenu)
if canDisplayAdminMenu || canDisplayAdminRedirect || canDisplaySplitTestMenu
li.dropdown.subdued
a.dropdown-toggle(
href="#",
role="button",
aria-haspopup="true",
aria-expanded="false",
data-toggle="dropdown"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": "admin", "location": "top-menu"}
href='#'
role='button'
aria-haspopup='true'
aria-expanded='false'
data-toggle='dropdown'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'admin', location: 'top-menu'}
)
| Admin
span.caret
ul.dropdown-menu
if canDisplayAdminMenu
li
a(href="/admin") Manage Site
a(href='/admin') Manage Site
li
a(href="/admin/user") Manage Users
a(href='/admin/user') Manage Users
li
a(href="/admin/project") Project URL Lookup
a(href='/admin/project') Project URL Lookup
if canDisplayAdminRedirect
li
a(href=settings.adminUrl) Switch to Admin
if canDisplaySplitTestMenu
li
a(href="/admin/split-test") Manage Feature Flags
a(href='/admin/split-test') Manage Feature Flags
if canDisplaySurveyMenu
li
a(href="/admin/survey") Manage Surveys
a(href='/admin/survey') Manage Surveys
if canDisplayScriptLogMenu
li
a(href="/admin/script-logs") View Script Logs
a(href='/admin/script-logs') View Script Logs
// loop over header_extras
each item in nav.header_extras
@@ -88,15 +97,15 @@ nav.navbar.navbar-default.navbar-main.website-redesign-navbar
if item.dropdown
li.dropdown(class=item.class)
a.dropdown-toggle(
href="#",
role="button",
aria-haspopup="true",
aria-expanded="false",
data-toggle="dropdown"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": item.trackingKey, "location": "top-menu"}
href='#'
role='button'
aria-haspopup='true'
aria-expanded='false'
data-toggle='dropdown'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: item.trackingKey, location: 'top-menu'}
)
| !{translate(item.text)}
span.caret
@@ -106,18 +115,25 @@ nav.navbar.navbar-default.navbar-main.website-redesign-navbar
li.divider
else if child.isContactUs
li
a(data-ol-open-contact-form-modal="contact-us" href event-tracking="menu-click" event-tracking-mb="true" event-tracking-trigger="click" event-segmentation={"item": "contact", "location": "top-menu"})
a(
data-ol-open-contact-form-modal='contact-us'
href
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'contact', location: 'top-menu'}
)
span
| #{translate("contact_us")}
else
li
if child.url
a(
href=child.url,
class=child.class,
event-tracking="menu-click"
event-tracking-mb="true"
event-tracking-trigger="click"
href=child.url
class=child.class
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: child.trackingKey, location: 'top-menu'}
) !{translate(child.text)}
else
@@ -126,12 +142,12 @@ nav.navbar.navbar-default.navbar-main.website-redesign-navbar
li(class=item.class)
if item.url
a(
href=item.url,
class=item.class,
event-tracking="menu-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ item: item.trackingKey, location: 'top-menu' }
href=item.url
class=item.class
event-tracking='menu-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: item.trackingKey, location: 'top-menu'}
) !{translate(item.text)}
else
| !{translate(item.text)}
@@ -142,54 +158,54 @@ nav.navbar.navbar-default.navbar-main.website-redesign-navbar
if hasFeature('registration-page')
li.primary
a(
href="/register"
event-tracking="menu-click"
event-tracking-action="clicked"
event-tracking-trigger="click"
event-tracking-mb="true"
event-segmentation={ page: currentUrl, item: 'register', location: 'top-menu' }
href='/register'
event-tracking='menu-click'
event-tracking-action='clicked'
event-tracking-trigger='click'
event-tracking-mb='true'
event-segmentation={page: currentUrl, item: 'register', location: 'top-menu'}
) #{translate('sign_up')}
// login link
li.secondary
a(
href="/login"
event-tracking="menu-click"
event-tracking-action="clicked"
event-tracking-trigger="click"
event-tracking-mb="true"
event-segmentation={ page: currentUrl, item: 'login', location: 'top-menu' }
href='/login'
event-tracking='menu-click'
event-tracking-action='clicked'
event-tracking-trigger='click'
event-tracking-mb='true'
event-segmentation={page: currentUrl, item: 'login', location: 'top-menu'}
) #{translate('log_in')}
// projects link and account menu
if getSessionUser()
li.secondary
a(href="/project") #{translate('Projects')}
a(href='/project') #{translate('Projects')}
li.secondary.dropdown
a.dropdown-toggle(
href="#",
role="button",
aria-haspopup="true",
aria-expanded="false",
data-toggle="dropdown"
event-tracking="menu-expand"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={"item": "account", "location": "top-menu"}
href='#'
role='button'
aria-haspopup='true'
aria-expanded='false'
data-toggle='dropdown'
event-tracking='menu-expand'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={item: 'account', location: 'top-menu'}
)
| #{translate('Account')}
span.caret
ul.dropdown-menu
li
div.subdued #{getSessionUser().email}
.subdued #{getSessionUser().email}
li.divider.hidden-xs.hidden-sm
li
a(href="/user/settings") #{translate('account_settings')}
a(href='/user/settings') #{translate('account_settings')}
if nav.showSubscriptionLink
li
a(href="/user/subscription") #{translate('subscription')}
a(href='/user/subscription') #{translate('subscription')}
li.divider.hidden-xs.hidden-sm
li
form(method="POST" action="/logout")
input(name='_csrf', type='hidden', value=csrfToken)
form(method='POST' action='/logout')
input(name='_csrf' type='hidden' value=csrfToken)
button.btn-link.text-left.dropdown-menu-button #{translate('log_out')}

View File

@@ -25,7 +25,7 @@ footer.site-footer
each item in nav.left_footer
li
if item.url
a(href=item.url, class=item.class) !{translate(item.text)}
a(href=item.url class=item.class) !{translate(item.text)}
else
| !{item.text}
@@ -33,6 +33,6 @@ footer.site-footer
each item in nav.right_footer
li
if item.url
a(href=item.url, class=item.class, aria-label=item.label) !{item.text}
a(href=item.url class=item.class aria-label=item.label) !{item.text}
else
| !{item.text}

View File

@@ -27,7 +27,7 @@ footer.site-footer
each item in nav.left_footer
li
if item.url
a(href=item.url, class=item.class) !{translate(item.text)}
a(href=item.url class=item.class) !{translate(item.text)}
else
| !{item.text}
@@ -35,6 +35,6 @@ footer.site-footer
each item in nav.right_footer
li
if item.url
a(href=item.url, class=item.class, aria-label=item.label) !{item.text}
a(href=item.url class=item.class aria-label=item.label) !{item.text}
else
| !{item.text}

View File

@@ -1,36 +1,36 @@
extends ../../layout-marketing
block vars
- var suppressFooter = true
- var suppressCookieBanner = true
- var suppressSkipToContent = true
- var suppressFooter = true
- var suppressCookieBanner = true
- var suppressSkipToContent = true
block content
.editor.full-size
.loading-screen()
.loading-screen-brand-container
.loading-screen-brand(
style="height: 20%;"
)
.editor.full-size
.loading-screen()
.loading-screen-brand-container
.loading-screen-brand(
style="height: 20%;"
)
h3.loading-screen-label() #{translate("Opening template")}
span.loading-screen-ellip .
span.loading-screen-ellip .
span.loading-screen-ellip .
h3.loading-screen-label() #{translate("Opening template")}
span.loading-screen-ellip .
span.loading-screen-ellip .
span.loading-screen-ellip .
form(
data-ol-regular-form
data-ol-auto-submit
method='POST'
action='/project/new/template/'
)
input(type="hidden", name="_csrf", value=csrfToken)
input(type="hidden" name="templateId" value=templateId)
input(type="hidden" name="templateVersionId" value=templateVersionId)
input(type="hidden" name="templateName" value=name)
input(type="hidden" name="compiler" value=compiler)
input(type="hidden" name="imageName" value=imageName)
input(type="hidden" name="mainFile" value=mainFile)
if brandVariationId
input(type="hidden" name="brandVariationId" value=brandVariationId)
input(hidden type="submit")
form(
data-ol-regular-form
data-ol-auto-submit
method='POST'
action='/project/new/template/'
)
input(type="hidden", name="_csrf", value=csrfToken)
input(type="hidden" name="templateId" value=templateId)
input(type="hidden" name="templateVersionId" value=templateVersionId)
input(type="hidden" name="templateName" value=name)
input(type="hidden" name="compiler" value=compiler)
input(type="hidden" name="imageName" value=imageName)
input(type="hidden" name="mainFile" value=mainFile)
if brandVariationId
input(type="hidden" name="brandVariationId" value=brandVariationId)
input(hidden type="submit")

View File

@@ -11,7 +11,7 @@ block vars
- metadata.robotsNoindexNofollow = true
block content
#pdf-preview-detached-root()
#pdf-preview-detached-root
block append meta
include editor/_meta

View File

@@ -15,7 +15,7 @@ block content
main#ide-root
.loading-screen
.loading-screen-brand-container
.loading-screen-brand(style="height: 20%;")
.loading-screen-brand(style='height: 20%')
h3.loading-screen-label #{translate("loading")}
span.loading-screen-ellip .
span.loading-screen-ellip .
@@ -25,4 +25,9 @@ block append meta
include editor/_meta
block prepend foot-scripts
script(type="text/javascript", nonce=scriptNonce, src=(wsUrl || '/socket.io') + '/socket.io.js', defer=deferScripts)
script(
type='text/javascript'
nonce=scriptNonce
src=(wsUrl || '/socket.io') + '/socket.io.js'
defer=deferScripts
)

View File

@@ -1,18 +1,18 @@
extends ../../layout-marketing
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-md-8.col-md-offset-2.offset-md-2
.card.project-invite-invalid
.card-body
.page-header.text-center
h1 #{translate("invite_not_valid")}
h1 #{translate("invite_not_valid")}
.row.text-center
.col-12.col-md-12
p
| #{translate("invite_not_valid_description")}.
.row.text-center.actions
.col-12.col-md-12
a.btn.btn-secondary-info.btn-secondary(href="/project") #{translate("back_to_your_projects")}
a.btn.btn-secondary-info.btn-secondary(href='/project') #{translate("back_to_your_projects")}

View File

@@ -1,7 +1,7 @@
extends ../../layout-marketing
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-12.col-md-8.col-md-offset-2.offset-md-2
@@ -20,16 +20,16 @@ block content
.col-12.col-md-12
form.form(
data-ol-regular-form
method="POST",
action="/project/"+invite.projectId+"/invite/token/"+token+"/accept"
method='POST'
action='/project/' + invite.projectId + '/invite/token/' + token + '/accept'
)
input(name='_csrf', type='hidden', value=csrfToken)
input(name='token', type='hidden', value=token)
input(name='_csrf' type='hidden' value=csrfToken)
input(name='token' type='hidden' value=token)
.form-group.text-center
button.btn.btn-lg.btn-primary(
type="submit"
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("join_project")}
span(hidden data-ol-inflight="pending") #{translate("joining")}…
span(data-ol-inflight='idle') #{translate("join_project")}
span(hidden data-ol-inflight='pending') #{translate("joining")}…
.form-group.text-center

View File

@@ -9,35 +9,83 @@ block vars
- const suppressFooter = true
block append meta
meta(name="ol-usersBestSubscription" data-type="json" content=usersBestSubscription)
meta(name="ol-notifications" data-type="json" content=notifications)
meta(name="ol-notificationsInstitution" data-type="json" content=notificationsInstitution)
meta(name="ol-userEmails" data-type="json" content=userEmails)
meta(name="ol-allInReconfirmNotificationPeriods" data-type="json" content=allInReconfirmNotificationPeriods)
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-userAffiliations" data-type="json" content=userAffiliations)
meta(name="ol-reconfirmedViaSAML" content=reconfirmedViaSAML)
meta(name="ol-survey" data-type="json" content=survey)
meta(name="ol-tags" data-type="json" content=tags)
meta(name="ol-portalTemplates" data-type="json" content=portalTemplates)
meta(name="ol-prefetchedProjectsBlob" data-type="json" content=prefetchedProjectsBlob)
if (suggestedLanguageSubdomainConfig)
meta(name="ol-suggestedLanguage" data-type="json" content=Object.assign(suggestedLanguageSubdomainConfig, {
lngName: translate(suggestedLanguageSubdomainConfig.lngCode),
imgUrl: buildImgPath("flags/24/" + suggestedLanguageSubdomainConfig.lngCode + ".png")
}))
meta(name="ol-currentUrl" data-type="string" content=currentUrl)
meta(name="ol-showGroupsAndEnterpriseBanner" data-type="boolean" content=showGroupsAndEnterpriseBanner)
meta(name="ol-groupsAndEnterpriseBannerVariant" data-type="string" content=groupsAndEnterpriseBannerVariant)
meta(name="ol-showInrGeoBanner" data-type="boolean" content=showInrGeoBanner)
meta(name="ol-showBrlGeoBanner" data-type="boolean" content=showBrlGeoBanner)
meta(name="ol-recommendedCurrency" data-type="string" content=recommendedCurrency)
meta(name="ol-showLATAMBanner" data-type="boolean" content=showLATAMBanner)
meta(name="ol-groupSubscriptionsPendingEnrollment" data-type="json" content=groupSubscriptionsPendingEnrollment)
meta(name="ol-hasIndividualPaidSubscription" data-type="boolean" content=hasIndividualPaidSubscription)
meta(name="ol-groupSsoSetupSuccess" data-type="boolean" content=groupSsoSetupSuccess)
meta(name="ol-showUSGovBanner" data-type="boolean" content=showUSGovBanner)
meta(name="ol-usGovBannerVariant" data-type="string" content=usGovBannerVariant)
meta(
name='ol-usersBestSubscription'
data-type='json'
content=usersBestSubscription
)
meta(name='ol-notifications' data-type='json' content=notifications)
meta(
name='ol-notificationsInstitution'
data-type='json'
content=notificationsInstitution
)
meta(name='ol-userEmails' data-type='json' content=userEmails)
meta(
name='ol-allInReconfirmNotificationPeriods'
data-type='json'
content=allInReconfirmNotificationPeriods
)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-userAffiliations' data-type='json' content=userAffiliations)
meta(name='ol-reconfirmedViaSAML' content=reconfirmedViaSAML)
meta(name='ol-survey' data-type='json' content=survey)
meta(name='ol-tags' data-type='json' content=tags)
meta(name='ol-portalTemplates' data-type='json' content=portalTemplates)
meta(
name='ol-prefetchedProjectsBlob'
data-type='json'
content=prefetchedProjectsBlob
)
if suggestedLanguageSubdomainConfig
meta(
name='ol-suggestedLanguage'
data-type='json'
content=Object.assign(suggestedLanguageSubdomainConfig, {
lngName: translate(suggestedLanguageSubdomainConfig.lngCode),
imgUrl: buildImgPath('flags/24/' + suggestedLanguageSubdomainConfig.lngCode + '.png'),
})
)
meta(name='ol-currentUrl' data-type='string' content=currentUrl)
meta(
name='ol-showGroupsAndEnterpriseBanner'
data-type='boolean'
content=showGroupsAndEnterpriseBanner
)
meta(
name='ol-groupsAndEnterpriseBannerVariant'
data-type='string'
content=groupsAndEnterpriseBannerVariant
)
meta(name='ol-showInrGeoBanner' data-type='boolean' content=showInrGeoBanner)
meta(name='ol-showBrlGeoBanner' data-type='boolean' content=showBrlGeoBanner)
meta(
name='ol-recommendedCurrency'
data-type='string'
content=recommendedCurrency
)
meta(name='ol-showLATAMBanner' data-type='boolean' content=showLATAMBanner)
meta(
name='ol-groupSubscriptionsPendingEnrollment'
data-type='json'
content=groupSubscriptionsPendingEnrollment
)
meta(
name='ol-hasIndividualPaidSubscription'
data-type='boolean'
content=hasIndividualPaidSubscription
)
meta(
name='ol-groupSsoSetupSuccess'
data-type='boolean'
content=groupSsoSetupSuccess
)
meta(name='ol-showUSGovBanner' data-type='boolean' content=showUSGovBanner)
meta(
name='ol-usGovBannerVariant'
data-type='string'
content=usGovBannerVariant
)
block content
#project-list-root

View File

@@ -7,11 +7,11 @@ block vars
- var suppressFooter = true
- var suppressCookieBanner = true
- var suppressSkipToContent = true
block append meta
meta(name="ol-postUrl" data-type="string" content=postUrl)
meta(name="ol-user" data-type="json" content=user)
meta(name='ol-postUrl' data-type='string' content=postUrl)
meta(name='ol-user' data-type='json' content=user)
block content
.content.content-alt#main-content
div#token-access-page
#main-content.content.content-alt
#token-access-page

View File

@@ -9,9 +9,9 @@ block vars
- var suppressSkipToContent = true
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-project_id" data-type="string" content=projectId)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-project_id' data-type='string' content=projectId)
block content
.content.content-alt#main-content
div#sharing-updates-page
#main-content.content.content-alt
#sharing-updates-page

View File

@@ -4,13 +4,17 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/add-seats'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-groupName", data-type="string", content=groupName)
meta(name="ol-subscriptionId", data-type="string", content=subscriptionId)
meta(name="ol-totalLicenses", data-type="number", content=totalLicenses)
meta(name="ol-isProfessional", data-type="boolean", content=isProfessional)
meta(name="ol-isCollectionMethodManual", data-type="boolean", content=isCollectionMethodManual)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-groupName' data-type='string' content=groupName)
meta(name='ol-subscriptionId' data-type='string' content=subscriptionId)
meta(name='ol-totalLicenses' data-type='number' content=totalLicenses)
meta(name='ol-isProfessional' data-type='boolean' content=isProfessional)
meta(
name='ol-isCollectionMethodManual'
data-type='boolean'
content=isCollectionMethodManual
)
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
#add-seats-root

View File

@@ -4,7 +4,7 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/canceled-subscription'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name='ol-user' data-type='json' content=user)
block content
main.content.content-alt#subscription-canceled-root
main#subscription-canceled-root.content.content-alt

View File

@@ -1,36 +1,91 @@
extends ../layout-react
block entrypointVar
- entrypoint = 'pages/user/subscription/dashboard'
- entrypoint = 'pages/user/subscription/dashboard'
block head-scripts
script(type="text/javascript", nonce=scriptNonce, src="https://js.recurly.com/v4/recurly.js")
script(
type='text/javascript'
nonce=scriptNonce
src='https://js.recurly.com/v4/recurly.js'
)
block append meta
meta(name="ol-subscription" data-type="json" content=personalSubscription)
meta(name="ol-userCanExtendTrial" data-type="boolean" content=userCanExtendTrial)
meta(name="ol-managedGroupSubscriptions" data-type="json" content=managedGroupSubscriptions)
meta(name="ol-memberGroupSubscriptions" data-type="json" content=memberGroupSubscriptions)
meta(name="ol-managedInstitutions" data-type="json" content=managedInstitutions)
meta(name="ol-managedPublishers" data-type="json" content=managedPublishers)
meta(name="ol-planCodesChangingAtTermEnd" data-type="json", content=planCodesChangingAtTermEnd)
meta(name="ol-currentInstitutionsWithLicence" data-type="json" content=currentInstitutionsWithLicence)
meta(name="ol-hasSubscription" data-type="boolean" content=hasSubscription)
meta(name="ol-fromPlansPage" data-type="boolean" content=fromPlansPage)
meta(name="ol-plans" data-type="json" content=plans)
meta(name="ol-groupSettingsAdvertisedFor" data-type="json" content=groupSettingsAdvertisedFor)
meta(name="ol-canUseFlexibleLicensing" data-type="boolean", content=canUseFlexibleLicensing)
meta(name="ol-showGroupDiscount" data-type="boolean", content=showGroupDiscount)
meta(name="ol-groupSettingsEnabledFor" data-type="json" content=groupSettingsEnabledFor)
meta(name="ol-hasAiAssistViaWritefull" data-type="boolean", content=hasAiAssistViaWritefull)
meta(name="ol-aiAssistViaWritefullSource" data-type="string", content=aiAssistViaWritefullSource)
meta(name="ol-user" data-type="json" content=user)
if (personalSubscription && personalSubscription.payment)
meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey)
meta(name="ol-stripeUKApiKey" content=settings.apis.stripeUK.publishableKey)
meta(name="ol-recommendedCurrency" content=personalSubscription.payment.currency)
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
meta(name='ol-subscription' data-type='json' content=personalSubscription)
meta(
name='ol-userCanExtendTrial'
data-type='boolean'
content=userCanExtendTrial
)
meta(
name='ol-managedGroupSubscriptions'
data-type='json'
content=managedGroupSubscriptions
)
meta(
name='ol-memberGroupSubscriptions'
data-type='json'
content=memberGroupSubscriptions
)
meta(
name='ol-managedInstitutions'
data-type='json'
content=managedInstitutions
)
meta(name='ol-managedPublishers' data-type='json' content=managedPublishers)
meta(
name='ol-planCodesChangingAtTermEnd'
data-type='json'
content=planCodesChangingAtTermEnd
)
meta(
name='ol-currentInstitutionsWithLicence'
data-type='json'
content=currentInstitutionsWithLicence
)
meta(name='ol-hasSubscription' data-type='boolean' content=hasSubscription)
meta(name='ol-fromPlansPage' data-type='boolean' content=fromPlansPage)
meta(name='ol-plans' data-type='json' content=plans)
meta(
name='ol-groupSettingsAdvertisedFor'
data-type='json'
content=groupSettingsAdvertisedFor
)
meta(
name='ol-canUseFlexibleLicensing'
data-type='boolean'
content=canUseFlexibleLicensing
)
meta(
name='ol-showGroupDiscount'
data-type='boolean'
content=showGroupDiscount
)
meta(
name='ol-groupSettingsEnabledFor'
data-type='json'
content=groupSettingsEnabledFor
)
meta(
name='ol-hasAiAssistViaWritefull'
data-type='boolean'
content=hasAiAssistViaWritefull
)
meta(
name='ol-aiAssistViaWritefullSource'
data-type='string'
content=aiAssistViaWritefullSource
)
meta(name='ol-user' data-type='json' content=user)
if personalSubscription && personalSubscription.payment
meta(name='ol-recurlyApiKey' content=settings.apis.recurly.publicKey)
meta(name='ol-stripeUKApiKey' content=settings.apis.stripeUK.publishableKey)
meta(
name='ol-recommendedCurrency'
content=personalSubscription.payment.currency
)
meta(name='ol-groupPlans' data-type='json' content=groupPlans)
block content
main.content.content-alt#main-content
#subscription-dashboard-root
main#main-content.content.content-alt
#subscription-dashboard-root

View File

@@ -4,8 +4,8 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/manually-collected-subscription'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-groupName", data-type="string", content=groupName)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-groupName' data-type='string' content=groupName)
block content
main.content.content-alt#manually-collected-subscription-root
main#manually-collected-subscription-root.content.content-alt

View File

@@ -4,8 +4,8 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/missing-billing-information'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-groupName", data-type="string", content=groupName)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-groupName' data-type='string' content=groupName)
block content
main.content.content-alt#missing-billing-information-root
main#missing-billing-information-root.content.content-alt

View File

@@ -9,7 +9,7 @@ include ../../_mixins/material_symbol
.row.row-spaced-extra-large
.col-md-12.faq-heading-container
h2
+eyebrow(translate("frequently_asked_questions"))
+eyebrow(translate('frequently_asked_questions'))
| #{translate("your_questions_answered")}
.row
@@ -18,74 +18,62 @@ include ../../_mixins/material_symbol
class={
'plans-faq-tabs': bootstrapVersion === 5,
'ol-tabs': bootstrapVersion === 5,
'ol-tabs-scrollable': bootstrapVersion === 3
'ol-tabs-scrollable': bootstrapVersion === 3,
}
)
.nav-tabs-container
ul.nav.nav-tabs(role="tablist")
ul.nav.nav-tabs(role='tablist')
//- In the bs5 version of plans page, the `active` class need to be added to the `a` tag instead of the parent `li` tag
//- If the `plans-page-bs5` split test has been completed, remove the `active` class from the `li` tag since we're not using it anymore
//- If the `plans-page-bs5` split test has been completed, remove the `data-toggle` because it is not needed anymore (bs5 uses `data-bs-toggle`)
li(
role="presentation"
class={
active: bootstrapVersion === 3
}
)
li(role='presentation' class={
active: bootstrapVersion === 3,
})
a(
role="tab"
data-toggle="tab"
data-bs-toggle="tab"
role='tab'
data-toggle='tab'
data-bs-toggle='tab'
href='#' + managingYourSubscription
aria-controls=managingYourSubscription
class={
active: bootstrapVersion === 5
active: bootstrapVersion === 5,
}
)
| #{translate('managing_your_subscription')}
li(role="presentation")
li(role='presentation')
a(
role="tab"
data-toggle="tab"
data-bs-toggle="tab"
role='tab'
data-toggle='tab'
data-bs-toggle='tab'
href='#' + overleafIndividualPlans
aria-controls=overleafIndividualPlans
)
| #{translate('overleaf_individual_plans')}
li(role="presentation")
li(role='presentation')
a(
role="tab"
data-toggle="tab"
data-bs-toggle="tab"
role='tab'
data-toggle='tab'
data-bs-toggle='tab'
href='#' + overleafGroupPlans
aria-controls=overleafGroupPlans
)
| #{translate('overleaf_group_plans')}
.tab-content
.tab-pane.active(
role="tabpanel"
id=managingYourSubscription
)
+managingYourSubscription()
.tab-pane(
role="tabpanel"
id=overleafIndividualPlans
)
+overleafIndividualPlans()
.tab-pane(
role="tabpanel"
id=overleafGroupPlans
)
+overleafGroupPlans()
.tab-pane.active(role='tabpanel' id=managingYourSubscription)
+managingYourSubscription
.tab-pane(role='tabpanel' id=overleafIndividualPlans)
+overleafIndividualPlans
.tab-pane(role='tabpanel' id=overleafGroupPlans)
+overleafGroupPlans
.row
.col-xs-12.plans-faq-support
span #{translate('still_have_questions')}
button(
data-ol-open-contact-form-modal="general"
data-bs-toggle=bootstrapVersion === 5 ? "modal" : undefined
data-bs-target=bootstrapVersion === 5 ? "#contactUsModal" : undefined
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')}
+material-symbol-rounded("arrow_right_alt", "icon-md")
span(style='margin-right: 4px') #{translate('contact_support')}
+material-symbol-rounded('arrow_right_alt', 'icon-md')

View File

@@ -1,357 +1,353 @@
//- If the `plans-page-bs5` split test has been completed, remove the `data-toggle` and `data-target` because it is not needed anymore (bs5 uses `data-bs-toggle` and `data-bs-target`)
include ../../_mixins/material_symbol
mixin managingYourSubscription()
mixin managingYourSubscription
.ol-accordions-container
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#managingYourSubscriptionQ1"
data-bs-toggle="collapse"
data-bs-target="#managingYourSubscriptionQ1"
aria-expanded="false"
aria-controls="managingYourSubscriptionQ1"
type='button'
data-toggle='collapse'
data-target='#managingYourSubscriptionQ1'
data-bs-toggle='collapse'
data-bs-target='#managingYourSubscriptionQ1'
aria-expanded='false'
aria-controls='managingYourSubscriptionQ1'
)
| Can I change plans or cancel later?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="managingYourSubscriptionQ1")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='managingYourSubscriptionQ1')
.custom-accordion-body
span Yes, you can do this at any time by going to
strong Account > Subscription
span Yes, you can do this at any time by going to
strong Account > Subscription
span when logged in to Overleaf. You can change plans, switch between monthly and annual billing options, or cancel to downgrade to the free plan. When canceling, your subscription will continue until the end of the billing period.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#managingYourSubscriptionQ2"
data-bs-toggle="collapse"
data-bs-target="#managingYourSubscriptionQ2"
aria-expanded="false"
aria-controls="managingYourSubscriptionQ2"
type='button'
data-toggle='collapse'
data-target='#managingYourSubscriptionQ2'
data-bs-toggle='collapse'
data-bs-target='#managingYourSubscriptionQ2'
aria-expanded='false'
aria-controls='managingYourSubscriptionQ2'
)
| If I change or cancel my Overleaf plan, will I lose my projects?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="managingYourSubscriptionQ2")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='managingYourSubscriptionQ2')
.custom-accordion-body
| No. Changing or canceling your plan wont affect your projects, the only change will be to the features available to you. You can see which features are available only on paid plans in the comparison table.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#managingYourSubscriptionQ3"
data-bs-toggle="collapse"
data-bs-target="#managingYourSubscriptionQ3"
aria-expanded="false"
aria-controls="managingYourSubscriptionQ3"
type='button'
data-toggle='collapse'
data-target='#managingYourSubscriptionQ3'
data-bs-toggle='collapse'
data-bs-target='#managingYourSubscriptionQ3'
aria-expanded='false'
aria-controls='managingYourSubscriptionQ3'
)
| Can I pay by invoice or purchase order?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="managingYourSubscriptionQ3")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='managingYourSubscriptionQ3')
.custom-accordion-body
| This is possible when youre purchasing a group subscription for five or more people, or a site license. For individual subscriptions, we can only accept payment online via credit card, debit card, or PayPal.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#managingYourSubscriptionQ4"
data-bs-toggle="collapse"
data-bs-target="#managingYourSubscriptionQ4"
aria-expanded="false"
aria-controls="managingYourSubscriptionQ4"
type='button'
data-toggle='collapse'
data-target='#managingYourSubscriptionQ4'
data-bs-toggle='collapse'
data-bs-target='#managingYourSubscriptionQ4'
aria-expanded='false'
aria-controls='managingYourSubscriptionQ4'
)
| How do I view/update the credit card being charged for my subscription?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="managingYourSubscriptionQ4")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='managingYourSubscriptionQ4')
.custom-accordion-body
| You can view and update the card on file by going to Account >
| You can view and update the card on file by going to Account >
a.inline-green-link(
target="_blank"
href="/user/subscription"
event-tracking="plans-page-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ button: 'contact', location: 'faq' }
target='_blank'
href='/user/subscription'
event-tracking='plans-page-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={button: 'contact', location: 'faq'}
)
span Subscription
| .
mixin overleafIndividualPlans()
mixin overleafIndividualPlans
.ol-accordions-container
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafIndividualPlansQ1"
data-bs-toggle="collapse"
data-bs-target="#overleafIndividualPlansQ1"
aria-expanded="false"
aria-controls="overleafIndividualPlansQ1"
type='button'
data-toggle='collapse'
data-target='#overleafIndividualPlansQ1'
data-bs-toggle='collapse'
data-bs-target='#overleafIndividualPlansQ1'
aria-expanded='false'
aria-controls='overleafIndividualPlansQ1'
)
| How does the free trial work?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafIndividualPlansQ1")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafIndividualPlansQ1')
.custom-accordion-body
span You get full access to your chosen plan during your 7-day free trial, and theres no obligation to continue beyond the trial. Your card will be charged at the end of your trial unless you cancel before then. To cancel, go to
strong Account >
span You get full access to your chosen plan during your 7-day free trial, and theres no obligation to continue beyond the trial. Your card will be charged at the end of your trial unless you cancel before then. To cancel, go to
strong Account >
|
a.inline-green-link(
target="_blank"
href="/user/subscription"
event-tracking="plans-page-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ button: 'contact', location: 'faq' }
target='_blank'
href='/user/subscription'
event-tracking='plans-page-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={button: 'contact', location: 'faq'}
)
span Subscription
span when logged in to Overleaf (the trial will continue for the full 7 days).
span when logged in to Overleaf (the trial will continue for the full 7 days).
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafIndividualPlansQ2"
data-bs-toggle="collapse"
data-bs-target="#overleafIndividualPlansQ2"
aria-expanded="false"
aria-controls="overleafIndividualPlansQ2"
type='button'
data-toggle='collapse'
data-target='#overleafIndividualPlansQ2'
data-bs-toggle='collapse'
data-bs-target='#overleafIndividualPlansQ2'
aria-expanded='false'
aria-controls='overleafIndividualPlansQ2'
)
| Whats a collaborator on an Overleaf individual subscription?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafIndividualPlansQ2")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafIndividualPlansQ2')
.custom-accordion-body
| A collaborator is someone you invite to work with you on a project. So, for example, on our Standard plan you can have up to 10 people collaborating with you on any given project.
| A collaborator is someone you invite to work with you on a project. So, for example, on our Standard plan you can have up to 10 people collaborating with you on any given project.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafIndividualPlansQ3"
data-bs-toggle="collapse"
data-bs-target="#overleafIndividualPlansQ3"
aria-expanded="false"
aria-controls="overleafIndividualPlansQ3"
type='button'
data-toggle='collapse'
data-target='#overleafIndividualPlansQ3'
data-bs-toggle='collapse'
data-bs-target='#overleafIndividualPlansQ3'
aria-expanded='false'
aria-controls='overleafIndividualPlansQ3'
)
| The individual Standard plan has 10 project collaborators, does it mean that 10 people will be upgraded?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafIndividualPlansQ3")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafIndividualPlansQ3')
.custom-accordion-body
span No. Only the subscribers account will be upgraded. An individual Standard subscription allows you to invite 10 people per project to edit the project with you. Your collaborators can access features such as the full document history and extended compile time, but
strong only
span No. Only the subscribers account will be upgraded. An individual Standard subscription allows you to invite 10 people per project to edit the project with you. Your collaborators can access features such as the full document history and extended compile time, but
strong only
span for the project(s) theyre working on with you. If your collaborators want access to those features on their own projects, they will need to purchase their own subscription. (If you work with the same people regularly, you might find a group subscription more cost effective.)
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafIndividualPlansQ4"
data-bs-toggle="collapse"
data-bs-target="#overleafIndividualPlansQ4"
aria-expanded="false"
aria-controls="overleafIndividualPlansQ4"
type='button'
data-toggle='collapse'
data-target='#overleafIndividualPlansQ4'
data-bs-toggle='collapse'
data-bs-target='#overleafIndividualPlansQ4'
aria-expanded='false'
aria-controls='overleafIndividualPlansQ4'
)
| Do collaborators also have access to the editing and collaboration features Ive paid for?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafIndividualPlansQ4")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafIndividualPlansQ4')
.custom-accordion-body
span If you have an Overleaf subscription, then your project collaborators will have access to features like real-time track changes and document history, but
strong only
span If you have an Overleaf subscription, then your project collaborators will have access to features like real-time track changes and document history, but
strong only
span for the project(s) theyre working on with you. If your collaborators want access to those features on their own projects, they will need to purchase their own subscription. (If you work with the same people regularly, you might find a group subscription more cost effective.)
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafIndividualPlansQ5"
data-bs-toggle="collapse"
data-bs-target="#overleafIndividualPlansQ5"
aria-expanded="false"
aria-controls="overleafIndividualPlansQ5"
type='button'
data-toggle='collapse'
data-target='#overleafIndividualPlansQ5'
data-bs-toggle='collapse'
data-bs-target='#overleafIndividualPlansQ5'
aria-expanded='false'
aria-controls='overleafIndividualPlansQ5'
)
| Can I purchase an individual plan on behalf of someone else?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafIndividualPlansQ5")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafIndividualPlansQ5')
.custom-accordion-body
| Individual subscriptions must be purchased by the account that will be the end user. If you want to purchase a plan for someone else, youll need to provide them with relevant payment details to enable them to make the purchase.
| Individual subscriptions must be purchased by the account that will be the end user. If you want to purchase a plan for someone else, youll need to provide them with relevant payment details to enable them to make the purchase.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafIndividualPlansQ6"
data-bs-toggle="collapse"
data-bs-target="#overleafIndividualPlansQ6"
aria-expanded="false"
aria-controls="overleafIndividualPlansQ6"
type='button'
data-toggle='collapse'
data-target='#overleafIndividualPlansQ6'
data-bs-toggle='collapse'
data-bs-target='#overleafIndividualPlansQ6'
aria-expanded='false'
aria-controls='overleafIndividualPlansQ6'
)
| Who is eligible for the Student plan?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafIndividualPlansQ6")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafIndividualPlansQ6')
.custom-accordion-body
| As the name suggests, the Student plan is only for students at educational institutions. This includes graduate students.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafIndividualPlansQ7"
data-bs-toggle="collapse"
data-bs-target="#overleafIndividualPlansQ7"
aria-expanded="false"
aria-controls="overleafIndividualPlansQ7"
type='button'
data-toggle='collapse'
data-target='#overleafIndividualPlansQ7'
data-bs-toggle='collapse'
data-bs-target='#overleafIndividualPlansQ7'
aria-expanded='false'
aria-controls='overleafIndividualPlansQ7'
)
| Can I transfer an individual subscription to someone else?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafIndividualPlansQ7")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafIndividualPlansQ7')
.custom-accordion-body
| No. Individual plans cant be transferred.
| No. Individual plans cant be transferred.
mixin overleafGroupPlans()
mixin overleafGroupPlans
.ol-accordions-container
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafGroupPlansQ1"
data-bs-toggle="collapse"
data-bs-target="#overleafGroupPlansQ1"
aria-expanded="false"
aria-controls="overleafGroupPlansQ1"
type='button'
data-toggle='collapse'
data-target='#overleafGroupPlansQ1'
data-bs-toggle='collapse'
data-bs-target='#overleafGroupPlansQ1'
aria-expanded='false'
aria-controls='overleafGroupPlansQ1'
)
| Whats the difference between users and collaborators on an Overleaf group subscription?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafGroupPlansQ1")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafGroupPlansQ1')
.custom-accordion-body
div On any of our group plans, the number of users refers to the number of people you can invite to join your group. All of these people will have access to the plans paid-for features across all their projects, such as real-time track changes and document history.
div.mt-2 Collaborators are people that your group users may invite to work with them on their projects. So, for example, if you have the Group Standard plan, the users in your group can invite up to 10 people to work with them on a project. And if you have the Group Professional plan, your users can invite as many people to work with them as they want.
div On any of our group plans, the number of users refers to the number of people you can invite to join your group. All of these people will have access to the plans paid-for features across all their projects, such as real-time track changes and document history.
.mt-2 Collaborators are people that your group users may invite to work with them on their projects. So, for example, if you have the Group Standard plan, the users in your group can invite up to 10 people to work with them on a project. And if you have the Group Professional plan, your users can invite as many people to work with them as they want.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafGroupPlansQ2"
data-bs-toggle="collapse"
data-bs-target="#overleafGroupPlansQ2"
aria-expanded="false"
aria-controls="overleafGroupPlansQ2"
type='button'
data-toggle='collapse'
data-target='#overleafGroupPlansQ2'
data-bs-toggle='collapse'
data-bs-target='#overleafGroupPlansQ2'
aria-expanded='false'
aria-controls='overleafGroupPlansQ2'
)
| What is the benefit of purchasing an Overleaf Group plan?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafGroupPlansQ2")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafGroupPlansQ2')
.custom-accordion-body
| Our Group subscriptions allow you to purchase access to our premium features for multiple people. Theyre easy to manage, help save on paperwork, and allow groups of 5 or more to purchase via purchase order (PO). We also offer discounts on purchases of Group subscriptions for more than 20 users; just get in touch with our
| Our Group subscriptions allow you to purchase access to our premium features for multiple people. Theyre easy to manage, help save on paperwork, and allow groups of 5 or more to purchase via purchase order (PO). We also offer discounts on purchases of Group subscriptions for more than 20 users; just get in touch with our
a.inline-green-link(
target="_blank"
href="/for/contact-sales"
event-tracking="plans-page-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ button: 'contact', location: 'faq' }
target='_blank'
href='/for/contact-sales'
event-tracking='plans-page-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={button: 'contact', location: 'faq'}
)
span Sales team
| .
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafGroupPlansQ3"
data-bs-toggle="collapse"
data-bs-target="#overleafGroupPlansQ3"
aria-expanded="false"
aria-controls="overleafGroupPlansQ3"
type='button'
data-toggle='collapse'
data-target='#overleafGroupPlansQ3'
data-bs-toggle='collapse'
data-bs-target='#overleafGroupPlansQ3'
aria-expanded='false'
aria-controls='overleafGroupPlansQ3'
)
| Who is eligible for the educational discount?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafGroupPlansQ3")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafGroupPlansQ3')
.custom-accordion-body
| The educational discount for group subscriptions is for students or faculty who are using Overleaf primarily for teaching.
| The educational discount for group subscriptions is for students or faculty who are using Overleaf primarily for teaching.
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafGroupPlansQ4"
data-bs-toggle="collapse"
data-bs-target="#overleafGroupPlansQ4"
aria-expanded="false"
aria-controls="overleafGroupPlansQ4"
type='button'
data-toggle='collapse'
data-target='#overleafGroupPlansQ4'
data-bs-toggle='collapse'
data-bs-target='#overleafGroupPlansQ4'
aria-expanded='false'
aria-controls='overleafGroupPlansQ4'
)
| How do I add more licenses to my group subscription, and what will it cost?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafGroupPlansQ4")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafGroupPlansQ4')
.custom-accordion-body
div
| You can add up to 20 licenses using the
div
| You can add up to 20 licenses using the
a.inline-green-link(
target="_blank"
href="/user/subscription"
event-tracking="plans-page-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ button: 'contact', location: 'faq' }
target='_blank'
href='/user/subscription'
event-tracking='plans-page-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={button: 'contact', location: 'faq'}
)
span subscription management page
| accessed by going to Account >
|
| accessed by going to Account >
a.inline-green-link(
target="_blank"
href="/user/subscription"
event-tracking="plans-page-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ button: 'contact', location: 'faq' }
target='_blank'
href='/user/subscription'
event-tracking='plans-page-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={button: 'contact', location: 'faq'}
)
span Subscription
| when logged into Overleaf. The cost per license will be prorated at the current per license rate, and will end with your existing renewal date.
div.mt-2
| If you need more than 20 licenses added to your subscription, please
|
| when logged into Overleaf. The cost per license will be prorated at the current per license rate, and will end with your existing renewal date.
.mt-2
| If you need more than 20 licenses added to your subscription, please
a.inline-green-link(
target="_blank"
href="/for/contact-sales"
event-tracking="plans-page-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ button: 'contact', location: 'faq' }
target='_blank'
href='/for/contact-sales'
event-tracking='plans-page-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={button: 'contact', location: 'faq'}
)
span contact the Sales team
| .
.custom-accordion-item
button.custom-accordion-header.collapsed(
type="button"
data-toggle="collapse"
data-target="#overleafGroupPlansQ5"
data-bs-toggle="collapse"
data-bs-target="#overleafGroupPlansQ5"
aria-expanded="false"
aria-controls="overleafGroupPlansQ5"
type='button'
data-toggle='collapse'
data-target='#overleafGroupPlansQ5'
data-bs-toggle='collapse'
data-bs-target='#overleafGroupPlansQ5'
aria-expanded='false'
aria-controls='overleafGroupPlansQ5'
)
| How do I upgrade my plan from Group Standard to Group Professional?
span.custom-accordion-icon
+material-symbol-outlined("keyboard_arrow_down")
.collapse(id="overleafGroupPlansQ5")
+material-symbol-outlined('keyboard_arrow_down')
.collapse(id='overleafGroupPlansQ5')
.custom-accordion-body
| You can upgrade your plan from Group Standard to Group Professional on the
| You can upgrade your plan from Group Standard to Group Professional on the
a.inline-green-link(
target="_blank"
href="/user/subscription"
event-tracking="plans-page-click"
event-tracking-mb="true"
event-tracking-trigger="click"
event-segmentation={ button: 'contact', location: 'faq' }
target='_blank'
href='/user/subscription'
event-tracking='plans-page-click'
event-tracking-mb='true'
event-tracking-trigger='click'
event-segmentation={button: 'contact', location: 'faq'}
)
span subscription management page
| .

View File

@@ -4,10 +4,14 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/preview-change'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-subscriptionChangePreview" data-type="json" content=changePreview)
meta(name="ol-purchaseReferrer" data-type="string" content=purchaseReferrer)
meta(name='ol-user' data-type='json' content=user)
meta(
name='ol-subscriptionChangePreview'
data-type='json'
content=changePreview
)
meta(name='ol-purchaseReferrer' data-type='string' content=purchaseReferrer)
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
#subscription-preview-change

View File

@@ -4,8 +4,8 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/subtotal-limit-exceeded'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-groupName", data-type="string", content=groupName)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-groupName' data-type='string' content=groupName)
block content
main.content.content-alt#subtotal-limit-exceeded-root
main#subtotal-limit-exceeded-root.content.content-alt

View File

@@ -4,9 +4,9 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/successful-subscription'
block append meta
meta(name="ol-subscription" data-type="json" content=personalSubscription)
meta(name="ol-postCheckoutRedirect" content=postCheckoutRedirect)
meta(name="ol-user" data-type="json" content=user)
meta(name='ol-subscription' data-type='json' content=personalSubscription)
meta(name='ol-postCheckoutRedirect' content=postCheckoutRedirect)
meta(name='ol-user' data-type='json' content=user)
block content
main.content.content-alt#subscription-success-root
main#subscription-success-root.content.content-alt

View File

@@ -4,8 +4,8 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-invites'
block append meta
meta(name="ol-teamInvites" data-type="json" content=teamInvites)
meta(name="ol-user" data-type="json" content=user)
meta(name='ol-teamInvites' data-type='json' content=teamInvites)
meta(name='ol-user' data-type='json' content=user)
block content
main.content.content-alt.team-invite#group-invites-root
main#group-invites-root.content.content-alt.team-invite

View File

@@ -4,16 +4,20 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/invite-managed'
block append meta
meta(name="ol-inviteToken" content=inviteToken)
meta(name="ol-inviterName" content=inviterName)
meta(name="ol-expired" data-type="boolean" content=expired)
meta(name="ol-alreadyEnrolled" data-type="boolean" content=alreadyEnrolled)
meta(name="ol-validationStatus" data-type="json" content=validationStatus)
meta(name="ol-currentManagedUserAdminEmail" data-type="string" content=currentManagedUserAdminEmail)
meta(name="ol-groupSSOActive" data-type="boolean" content=groupSSOActive)
meta(name="ol-subscriptionId" data-type="string" content=subscriptionId)
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-usersSubscription" data-type="json" content=usersSubscription)
meta(name='ol-inviteToken' content=inviteToken)
meta(name='ol-inviterName' content=inviterName)
meta(name='ol-expired' data-type='boolean' content=expired)
meta(name='ol-alreadyEnrolled' data-type='boolean' content=alreadyEnrolled)
meta(name='ol-validationStatus' data-type='json' content=validationStatus)
meta(
name='ol-currentManagedUserAdminEmail'
data-type='string'
content=currentManagedUserAdminEmail
)
meta(name='ol-groupSSOActive' data-type='boolean' content=groupSSOActive)
meta(name='ol-subscriptionId' data-type='string' content=subscriptionId)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-usersSubscription' data-type='json' content=usersSubscription)
block content
main.content.content-alt.team-invite#invite-managed-root
main#invite-managed-root.content.content-alt.team-invite

View File

@@ -4,14 +4,22 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/invite'
block append meta
meta(name="ol-hasIndividualPaidSubscription" data-type="boolean" content=hasIndividualPaidSubscription)
meta(name="ol-inviterName" data-type="string" content=inviterName)
meta(name="ol-inviteToken" data-type="string" content=inviteToken)
meta(name="ol-currentManagedUserAdminEmail" data-type="string" content=currentManagedUserAdminEmail)
meta(name="ol-expired" data-type="boolean" content=expired)
meta(name="ol-groupSSOActive" data-type="boolean" content=groupSSOActive)
meta(name="ol-subscriptionId" data-type="string" content=subscriptionId)
meta(name="ol-user" data-type="json" content=user)
meta(
name='ol-hasIndividualPaidSubscription'
data-type='boolean'
content=hasIndividualPaidSubscription
)
meta(name='ol-inviterName' data-type='string' content=inviterName)
meta(name='ol-inviteToken' data-type='string' content=inviteToken)
meta(
name='ol-currentManagedUserAdminEmail'
data-type='string'
content=currentManagedUserAdminEmail
)
meta(name='ol-expired' data-type='boolean' content=expired)
meta(name='ol-groupSSOActive' data-type='boolean' content=groupSSOActive)
meta(name='ol-subscriptionId' data-type='string' content=subscriptionId)
meta(name='ol-user' data-type='json' content=user)
block content
main.content.content-alt#invite-root
main#invite-root.content.content-alt

View File

@@ -1,12 +1,12 @@
extends ../../layout-marketing
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name='ol-user' data-type='json' content=user)
block content
- var colClass = bootstrapVersion === 5 ? 'col-lg-8 m-auto' : 'col-md-8 col-md-offset-2'
main.content.content-alt.team-invite#main-content
main#main-content.content.content-alt.team-invite
.container
.row
div(class=colClass)
@@ -16,15 +16,19 @@ block content
// TODO: Remove `team-invite-name` once we fully migrated to Bootstrap 5
h1.text-center !{translate("invited_to_group", {inviterName: inviterName, appName: appName }, [{name: 'span', attrs: {class: 'team-invite-name'}}])}
if (accountExists)
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")}
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")}
a.btn.btn-primary(
href=`/register?redir=/subscription/invites/${inviteToken}${groupSSOActive ? "&hide_sso_login=true" : ""}`
) #{translate("register_to_accept_invitation")}

View File

@@ -4,10 +4,14 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/upgrade-group-subscription'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-subscriptionChangePreview" data-type="json" content=changePreview)
meta(name="ol-totalLicenses", data-type="number", content=totalLicenses)
meta(name="ol-groupName", data-type="string", content=groupName)
meta(name='ol-user' data-type='json' content=user)
meta(
name='ol-subscriptionChangePreview'
data-type='json'
content=changePreview
)
meta(name='ol-totalLicenses' data-type='number' content=totalLicenses)
meta(name='ol-groupName' data-type='string' content=groupName)
block content
main.content.content-alt#upgrade-group-subscription-root
main#upgrade-group-subscription-root.content.content-alt

View File

@@ -6,7 +6,7 @@ block vars
- metadata.robotsNoindexNofollow = true
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container-custom-sm.mx-auto
.card
.card-body

View File

@@ -9,5 +9,5 @@ block entrypointVar
- entrypoint = 'pages/compromised-password'
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
#compromised-password

View File

@@ -8,7 +8,7 @@ block entrypointVar
- entrypoint = 'pages/user/confirm-secondary-email'
block append meta
meta(name="ol-email" content=email)
meta(name='ol-email' content=email)
block content
main.content.content-alt

View File

@@ -2,56 +2,50 @@ extends ../layout-marketing
include ../_mixins/notification
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-lg-8.offset-lg-2.col-xl-6.offset-xl-3
.card
.card-body
.page-header(data-ol-hide-on-error-message="confirm-email-wrong-user")
.page-header(data-ol-hide-on-error-message='confirm-email-wrong-user')
h1 #{translate("confirm_email")}
form(method='POST' action='/logout' id='logoutForm')
input(name='_csrf' type='hidden' value=csrfToken)
input(name='redirect' type='hidden' value=currentUrlWithQueryParams)
form(
method="POST"
action="/logout"
id="logoutForm"
name='confirmEmailForm'
data-ol-async-form
data-ol-auto-submit
action='/user/emails/confirm'
method='POST'
id='confirmEmailForm'
)
input(type="hidden", name="_csrf", value=csrfToken)
input(type="hidden", name="redirect", value=currentUrlWithQueryParams)
form(
data-ol-async-form,
data-ol-auto-submit,
name="confirmEmailForm"
action="/user/emails/confirm",
method="POST",
id="confirmEmailForm",
)
input(type="hidden", name="_csrf", value=csrfToken)
input(type="hidden", name="token", value=token)
input(name='_csrf' type='hidden' value=csrfToken)
input(name='token' type='hidden' value=token)
div(data-ol-not-sent)
+formMessages()
div(data-ol-custom-form-message="confirm-email-wrong-user" hidden)
+formMessages
div(data-ol-custom-form-message='confirm-email-wrong-user' hidden)
h1.h3 #{translate("we_cant_confirm_this_email")}
p !{translate("to_confirm_email_address_you_must_be_logged_in_with_the_requesting_account")}
p !{translate("you_are_currently_logged_in_as", {email: getUserEmail()})}
.actions
button.btn-primary.btn.w-100(
form="logoutForm"
) #{translate('log_in_with_a_different_account')}
button.btn-primary.btn.w-100(form='logoutForm') #{translate('log_in_with_a_different_account')}
.actions
button.btn-primary.btn.w-100(
type='submit',
type='submit'
data-ol-disabled-inflight
data-ol-hide-on-error-message="confirm-email-wrong-user"
data-ol-hide-on-error-message='confirm-email-wrong-user'
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate('confirm')}
span(hidden data-ol-inflight="pending")
span(role='status').spinner-border.spinner-border-sm.mx-2
span(hidden data-ol-inflight='pending')
span.spinner-border.spinner-border-sm.mx-2(role='status')
div(hidden data-ol-sent)
+notification({ariaLive: 'polite', type: 'success', className: 'mb-3', content: translate("thank_you_email_confirmed")})
div.text-center
a.btn.btn-primary(href="/user/settings")
+notification({ariaLive: 'polite', type: 'success', className: 'mb-3', content: translate('thank_you_email_confirmed')})
.text-center
a.btn.btn-primary(href='/user/settings')
| #{translate('go_to_account_settings')}

View File

@@ -2,7 +2,7 @@ extends ../layout-marketing
include ../_mixins/back_to_btns
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-lg-10.offset-lg-1.col-xl-8.offset-xl-2
@@ -10,9 +10,9 @@ block content
.card-body
.page-header
h1 #{translate("newsletter_info_title")}
p #{translate("newsletter_info_summary")}
- var submitAction
if subscribed
- submitAction = '/user/newsletter/unsubscribe'
@@ -20,28 +20,28 @@ block content
else
- submitAction = '/user/newsletter/subscribe'
p !{translate("newsletter_info_unsubscribed", {}, ['strong'])}
form(
name='newsletterForm'
data-ol-async-form
data-ol-reload-on-success
name="newsletterForm"
action=submitAction
method="POST"
method='POST'
)
input(name='_csrf', type='hidden', value=csrfToken)
+formMessages()
input(name='_csrf' type='hidden' value=csrfToken)
+formMessages
p.actions.text-center
if subscribed
button.btn-danger.btn(type='submit', data-ol-disabled-inflight)
span(data-ol-inflight="idle") #{translate("unsubscribe")}
span(hidden data-ol-inflight="pending") #{translate("saving")}…
button.btn-danger.btn(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("unsubscribe")}
span(hidden data-ol-inflight='pending') #{translate("saving")}…
else
button.btn-primary.btn(type='submit', data-ol-disabled-inflight)
span(data-ol-inflight="idle") #{translate("subscribe")}
span(hidden data-ol-inflight="pending") #{translate("saving")}…
button.btn-primary.btn(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("subscribe")}
span(hidden data-ol-inflight='pending') #{translate("saving")}…
if subscribed
p #{translate("newsletter_info_note")}
.page-separator
+back-to-btns()
+back-to-btns

View File

@@ -1,7 +1,7 @@
extends ../layout-marketing
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-lg-6.offset-lg-3.col-xl-4.offset-xl-4
@@ -11,10 +11,10 @@ block content
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()
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')
@@ -23,28 +23,24 @@ block content
| !{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"
name='email'
type='email'
required
placeholder='email@example.com'
autofocus='true'
)
.form-group
input.form-control(
type='password',
name='password',
required,
placeholder='********',
name='password'
type='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")}…
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}
p.text-center !{login_support_text}

View File

@@ -1,7 +1,7 @@
extends ../layout-marketing
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-lg-6.offset-lg-3.col-xl-4.offset-xl-4
@@ -13,6 +13,6 @@ block content
p
| Please
|
a(href="/login") log in
a(href='/login') log in
|
| to continue working on your projects.

View File

@@ -11,51 +11,55 @@ block content
- 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")
script(
type='text/javascript'
nonce=scriptNonce
src='https://www.recaptcha.net/recaptcha/api.js?render=explicit'
)
div(
id="recaptcha"
class="g-recaptcha"
id='recaptcha'
class='g-recaptcha'
data-sitekey=settings.recaptcha.siteKey
data-size="invisible"
data-badge="inline"
data-size='invisible'
data-badge='inline'
)
main#main-content(data-ol-captcha-retry-trigger-area="")
a.auth-aux-logo(href="/")
img(src=buildImgPath("ol-brand/overleaf-o-dark.svg") alt=settings.appName)
main#main-content(data-ol-captcha-retry-trigger-area='')
a.auth-aux-logo(href='/')
img(src=buildImgPath('ol-brand/overleaf-o-dark.svg') alt=settings.appName)
.auth-aux-container
form(
name='passwordResetForm'
captcha-action-name=showCaptcha ? 'passwordReset' : false
data-ol-async-form
name="passwordResetForm"
action="/user/password/reset"
method="POST"
captcha=(showCaptcha ? '' : false)
captcha-action-name=(showCaptcha ? "passwordReset" : false)
action='/user/password/reset'
method='POST'
captcha=showCaptcha ? '' : false
)
if error === 'password_reset_token_expired'
h1.h3.mb-3.mt-0 #{translate("sorry_your_token_expired")}
p #{translate('please_request_a_new_password_reset_email_and_follow_the_link')}.
else
h1.h3.mb-3.mt-0(data-ol-not-sent) #{translate("password_reset_sentence_case")}
h1.h3.mb-3.mt-0(hidden data-ol-sent) #{translate("check_your_email")}
h1.h3.mb-3.mt-0(hidden data-ol-sent) #{translate("check_your_email")}
p.mb-3.pb-3(data-ol-not-sent) #{translate("enter_your_email_address_below_and_we_will_send_you_a_link_to_reset_your_password")}.
div(data-ol-not-sent)
+formMessagesNewStyle()
+formMessagesNewStyle
if error && error !== 'password_reset_token_expired'
+notification({ariaLive: 'assertive', type: 'error', className: 'mb-3', content: translate(error)})
div(data-ol-custom-form-message="no-password-allowed-due-to-sso" hidden)
+notification({ariaLive: 'polite', type: 'error', className: 'mb-3', content: translate("you_cant_reset_password_due_to_sso", {}, [{name: 'a', attrs: {href: '/sso-login'}}])})
input(type="hidden" name="_csrf" value=csrfToken)
div(data-ol-custom-form-message='no-password-allowed-due-to-sso' hidden)
+notification({ariaLive: 'polite', type: 'error', className: 'mb-3', content: translate('you_cant_reset_password_due_to_sso', {}, [{name: 'a', attrs: {href: '/sso-login'}}])})
input(name='_csrf' type='hidden' value=csrfToken)
.form-group.mb-3
label.form-label(for='email') #{translate("email")}
input.form-control#email(
aria-label="email"
type='email'
input#email.form-control(
name='email'
aria-label='email'
type='email'
required
autocomplete="username"
autocomplete='username'
autofocus
)
.actions
@@ -64,14 +68,14 @@ block content
data-ol-disabled-inflight
aria-label=translate('reset_password_sentence_case')
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate("reset_password_sentence_case")}
span(hidden data-ol-inflight="pending")
span(hidden data-ol-inflight='pending')
| #{translate("requesting_password_reset")}…
a.btn.btn-ghost.w-100.mb-3(href="/login") #{translate("back_to_log_in")}
a.btn.btn-ghost.w-100.mb-3(href='/login') #{translate("back_to_log_in")}
div(hidden data-ol-sent)
p.mb-4 #{translate('password_reset_email_sent')}
a.btn.btn-primary.w-100.mb-3(href="/login") #{translate('back_to_log_in')}
a.btn.btn-primary.w-100.mb-3(href='/login') #{translate('back_to_log_in')}
if showCaptcha
+recaptchaConditions

View File

@@ -9,77 +9,81 @@ block content
- 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")
script(
type='text/javascript'
nonce=scriptNonce
src='https://www.recaptcha.net/recaptcha/api.js?render=explicit'
)
div(
id="recaptcha"
class="g-recaptcha"
id='recaptcha'
class='g-recaptcha'
data-sitekey=settings.recaptcha.siteKey
data-size="invisible"
data-badge="inline"
data-size='invisible'
data-badge='inline'
)
main.content.content-alt#main-content(data-ol-captcha-retry-trigger-area="")
main#main-content.content.content-alt(data-ol-captcha-retry-trigger-area='')
.container-custom-sm.mx-auto
.card
form(
name='passwordResetForm'
captcha-action-name=showCaptcha ? 'passwordReset' : false
data-ol-async-form
name="passwordResetForm"
action="/user/password/reset",
method="POST",
captcha=(showCaptcha ? '' : false),
captcha-action-name=(showCaptcha ? "passwordReset" : false),
action='/user/password/reset'
method='POST'
captcha=showCaptcha ? '' : false
)
if error === 'password_reset_token_expired'
h3.mt-0.mb-2 #{translate("sorry_your_token_expired")}
p #{translate('please_request_a_new_password_reset_email_and_follow_the_link')}.
else
h3.mt-0.mb-2(data-ol-not-sent) #{translate("password_reset")}
h3.mt-0.mb-2(hidden data-ol-sent) #{translate("check_your_email")}
h3.mt-0.mb-2(hidden data-ol-sent) #{translate("check_your_email")}
p(data-ol-not-sent) #{translate("enter_your_email_address_below_and_we_will_send_you_a_link_to_reset_your_password")}.
div(data-ol-not-sent)
+formMessages()
+formMessages
if error && error !== 'password_reset_token_expired'
div.alert.alert-danger.mb-2(
role="alert"
aria-live="assertive"
)
.alert.alert-danger.mb-2(role='alert' aria-live='assertive')
| #{translate(error)}
div(data-ol-custom-form-message="no-password-allowed-due-to-sso" hidden)
.notification.notification-type-error(aria-live="polite" style="margin-bottom: 10px;")
div(data-ol-custom-form-message='no-password-allowed-due-to-sso' hidden)
.notification.notification-type-error(
aria-live='polite'
style='margin-bottom: 10px'
)
.notification-icon
+material-symbol-rounded("error")
+material-symbol-rounded('error')
.notification-content-and-cta
.notification-content
p
| !{translate("you_cant_reset_password_due_to_sso", {}, [{name: 'a', attrs: {href: '/sso-login'}}])}
input(type="hidden", name="_csrf", value=csrfToken)
input(name='_csrf' type='hidden' value=csrfToken)
.form-group.mb-3
label(for='email') #{translate("email")}
input.form-control#email(
aria-label="email"
type='email',
name='email',
placeholder=translate("enter_your_email_address"),
required,
autocomplete="username",
input#email.form-control(
name='email'
aria-label='email'
type='email'
placeholder=translate('enter_your_email_address')
required
autocomplete='username'
autofocus
)
.actions
button.btn.btn-primary.w-100(
type='submit',
data-ol-disabled-inflight,
type='submit'
data-ol-disabled-inflight
aria-label=translate('request_password_reset_to_reconfirm')
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate("request_password_reset")}
span(hidden data-ol-inflight="pending")
span(hidden data-ol-inflight='pending')
| #{translate("requesting_password_reset")}…
div(hidden data-ol-sent)
p.mb-4 #{translate('password_reset_email_sent')}
a(href="/login") #{translate('back_to_log_in')}
a(href='/login') #{translate('back_to_log_in')}
if showCaptcha
+recaptchaConditions

View File

@@ -7,36 +7,36 @@ block vars
block content
main#main-content
.auth-aux-container
img.w-50.d-block(src=buildImgPath("ol-brand/overleaf.svg") alt=settings.appName)
img.w-50.d-block(
src=buildImgPath('ol-brand/overleaf.svg')
alt=settings.appName
)
h1.h3.mb-3 #{translate("keep_your_account_safe")}
div(data-ol-multi-submit)
p.small.mb-4
| !{translate("primary_email_check_question", { email: getUserEmail() }, ["strong"])}
form(
data-ol-async-form
action="/user/emails/primary-email-check"
method="POST"
action='/user/emails/primary-email-check'
method='POST'
)
input(name='_csrf', type='hidden', value=csrfToken)
+formMessagesNewStyle()
input(name='_csrf' type='hidden' value=csrfToken)
+formMessagesNewStyle
button.btn.btn-primary.w-100.mb-3(
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("yes_that_is_correct")}
span(hidden data-ol-inflight="pending") #{translate("confirming")}…
button.btn.btn-primary.w-100.mb-3(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("yes_that_is_correct")}
span(hidden data-ol-inflight='pending') #{translate("confirming")}…
a.btn.btn-secondary.w-100.mb-4(
href="/user/settings#add-email"
href='/user/settings#add-email'
data-ol-slow-link
event-tracking="primary-email-check-change-email"
event-tracking-mb="true"
event-tracking-trigger="click"
event-tracking='primary-email-check-change-email'
event-tracking-mb='true'
event-tracking-trigger='click'
)
span(data-ol-inflight="idle") #{translate("no_update_email")}
span(hidden data-ol-inflight="pending") #{translate("redirecting")}…
span(data-ol-inflight='idle') #{translate("no_update_email")}
span(hidden data-ol-inflight='pending') #{translate("redirecting")}…
p.small.mb-2
| #{translate("keep_your_email_updated")}
| #{translate("keep_your_email_updated")}
p.small
| !{translate("learn_more_about_emails", {}, [{name: 'a', attrs: {href: '/learn/how-to/Keeping_your_account_secure', 'event-tracking': 'primary-email-check-learn-more', 'event-tracking-mb': 'true', 'event-tracking-trigger': 'click' }}])}
| !{translate("learn_more_about_emails", {}, [{name: 'a', attrs: {href: '/learn/how-to/Keeping_your_account_secure', 'event-tracking': 'primary-email-check-learn-more', 'event-tracking-mb': 'true', 'event-tracking-trigger': 'click' }}])}

View File

@@ -5,46 +5,50 @@ block vars
- isWebsiteRedesign = true
block content
- var email = reconfirm_email ? reconfirm_email : ""
- 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")
script(
type='text/javascript'
nonce=scriptNonce
src='https://www.recaptcha.net/recaptcha/api.js?render=explicit'
)
div(
id="recaptcha"
class="g-recaptcha"
id='recaptcha'
class='g-recaptcha'
data-sitekey=settings.recaptcha.siteKey
data-size="invisible"
data-badge="inline"
data-size='invisible'
data-badge='inline'
)
main#main-content(data-ol-captcha-retry-trigger-area="")
.container.auth-aux-container(style="max-width: 420px;")
main#main-content(data-ol-captcha-retry-trigger-area='')
.container.auth-aux-container(style='max-width: 420px')
form(
name='reconfirmAccountForm'
captcha-action-name=showCaptcha ? 'passwordReset' : false
data-ol-async-form
name="reconfirmAccountForm"
action="/user/reconfirm"
method="POST"
action='/user/reconfirm'
method='POST'
aria-label=translate('request_reconfirmation_email')
captcha=(showCaptcha ? '' : false)
captcha-action-name=(showCaptcha ? "passwordReset" : false)
captcha=showCaptcha ? '' : 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)
div(data-ol-not-sent)
+formMessagesNewStyle
input(name='_csrf' type='hidden' 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'
aria-label='email'
type='email'
placeholder='email@example.com'
required
autofocus
@@ -52,20 +56,17 @@ block content
)
.actions
button.btn.btn-primary.w-100(
style="white-space: normal;"
style='white-space: normal'
type='submit'
data-ol-disabled-inflight
aria-label=translate('request_password_reset_to_reconfirm')
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate('request_password_reset_to_reconfirm')}
span(hidden data-ol-inflight="pending")
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"
)
.alert.alert-success(role='alert' aria-live='polite')
span #{translate('password_reset_email_sent')}
if showCaptcha

View File

@@ -5,20 +5,24 @@ block vars
- bootstrap5PageStatus = 'disabled'
block content
- var email = reconfirm_email ? reconfirm_email : ""
- 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")
script(
type='text/javascript'
nonce=scriptNonce
src='https://www.recaptcha.net/recaptcha/api.js?render=explicit'
)
div(
id="recaptcha"
class="g-recaptcha"
id='recaptcha'
class='g-recaptcha'
data-sitekey=settings.recaptcha.siteKey
data-size="invisible"
data-badge="inline"
data-size='invisible'
data-badge='inline'
)
main.content.content-alt#main-content(data-ol-captcha-retry-trigger-area="")
main#main-content.content.content-alt(data-ol-captcha-retry-trigger-area='')
.container
.row
.col-sm-12.col-md-6.col-md-offset-3
@@ -28,44 +32,41 @@ block content
a(href=`mailto:${settings.adminEmail}`) #{settings.adminEmail}
| .
form(
name='reconfirmAccountForm'
captcha-action-name=showCaptcha ? 'passwordReset' : false
data-ol-async-form
name="reconfirmAccountForm"
action="/user/reconfirm",
method="POST",
action='/user/reconfirm'
method='POST'
aria-label=translate('request_reconfirmation_email')
captcha=(showCaptcha ? '' : false),
captcha-action-name=(showCaptcha ? "passwordReset" : false)
captcha=showCaptcha ? '' : false
)
div(data-ol-not-sent)
+formMessages()
input(type="hidden", name="_csrf", value=csrfToken)
+formMessages
input(name='_csrf' type='hidden' value=csrfToken)
.form-group
label(for='email') #{translate("please_enter_email")}
input.form-control(
aria-label="email"
type='email',
name='email',
placeholder='email@example.com',
required,
name='email'
aria-label='email'
type='email'
placeholder='email@example.com'
required
autofocus
value=email
)
.actions
button.btn.btn-primary(
type='submit',
data-ol-disabled-inflight,
type='submit'
data-ol-disabled-inflight
aria-label=translate('request_password_reset_to_reconfirm')
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate('request_password_reset_to_reconfirm')}
span(hidden data-ol-inflight="pending")
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"
)
.alert.alert-success(role='alert' aria-live='polite')
span #{translate('password_reset_email_sent')}
.row
.col-sm-12.col-md-6.col-md-offset-3

View File

@@ -4,7 +4,7 @@ block vars
- bootstrap5PageStatus = 'disabled'
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.registration_message
@@ -15,12 +15,12 @@ block content
| #{translate("join_sl_to_view_project")}.
div
| #{translate("already_have_sl_account")}
a(href="/login") #{translate("login_here")}
a(href='/login') #{translate("login_here")}
else if newTemplateData.templateName !== undefined
h1 #{translate("register_to_edit_template", {templateName:newTemplateData.templateName})}
div #{translate("already_have_sl_account")}
a(href="/login") #{translate("login_here")}
a(href='/login') #{translate("login_here")}
.row
.col-md-8.col-md-offset-2.col-lg-6.col-lg-offset-3

View File

@@ -1,15 +1,15 @@
extends ../layout-marketing
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-lg-10.offset-lg-1.col-xl-8.offset-xl-2
.card.clear-user-sessions
.card-body
.page-header
h1 #{translate("your_sessions")}
h1 #{translate("your_sessions")}
if currentSession.ip_address && currentSession.session_created
h3 #{translate("current_session")}
div
@@ -21,47 +21,43 @@ block content
tr
td #{currentSession.ip_address}
td #{moment(currentSession.session_created).utc().format('Do MMM YYYY, h:mm a')} UTC
h3 #{translate("other_sessions")}
div
p.small
| !{translate("clear_sessions_description")}
form(
data-ol-async-form
action='/user/sessions/clear'
method='POST'
)
form(data-ol-async-form action='/user/sessions/clear' method='POST')
input(name='_csrf' type='hidden' value=csrfToken)
div(data-ol-not-sent)
if sessions.length == 0
p.text-center
| #{translate("no_other_sessions")}
if sessions.length > 0
table.table.table-striped
thead
tr
th #{translate("ip_address")}
th #{translate("session_created_at")}
for session in sessions
each session in sessions
tr
td #{session.ip_address}
td #{moment(session.session_created).utc().format('Do MMM YYYY, h:mm a')} UTC
p.actions
.text-center
button.btn.btn-lg.btn-primary(
type="submit"
type='submit'
data-ol-disable-inflight
)
span(data-ol-inflight="idle") #{translate('clear_sessions')}
span(hidden data-ol-inflight="pending") #{translate("processing")}…
span(data-ol-inflight='idle') #{translate('clear_sessions')}
span(hidden data-ol-inflight='pending') #{translate("processing")}…
div(hidden data-ol-sent)
p.text-center
| #{translate("no_other_sessions")}
p.text-success.text-center
| #{translate('clear_sessions_success')}
.page-separator

View File

@@ -7,28 +7,25 @@ block vars
block content
main#main-content
a.auth-aux-logo(href="/")
img(src=buildImgPath("ol-brand/overleaf-o-dark.svg") alt=settings.appName)
a.auth-aux-logo(href='/')
img(src=buildImgPath('ol-brand/overleaf-o-dark.svg') alt=settings.appName)
.auth-aux-container
form(
name='passwordResetForm'
data-ol-async-form
name="passwordResetForm"
action="/user/password/set"
method="POST"
data-ol-hide-on-error="token-expired"
action='/user/password/set'
method='POST'
data-ol-hide-on-error='token-expired'
)
div(
hidden
data-ol-sent
)
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()
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')}.
@@ -41,18 +38,21 @@ block content
+customFormMessageNewStyle('token-expired', 'danger')
| #{translate('password_reset_token_expired')}
br
a(href="/user/password/reset")
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(name='_csrf' type='hidden' value=csrfToken)
input(name='email' type='text' hidden 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'
label.form-label(
for='passwordField'
data-ol-hide-on-error-message='token-expired'
) #{translate("new_password")}
input#passwordField.form-control.auth-aux-new-password(
name='password'
autocomplete="new-password"
type='password'
autocomplete='new-password'
autofocus
required
minlength=settings.passwordStrengthOptions.length.min
@@ -68,12 +68,8 @@ block content
| !{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")
input(name='passwordResetToken' type='hidden' 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})}
@@ -85,7 +81,7 @@ block content
data-ol-disabled-inflight
aria-label=translate('set_new_password')
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate('set_new_password')}
span(hidden data-ol-inflight="pending")
span(hidden data-ol-inflight='pending')
| #{translate('set_new_password')}…

View File

@@ -4,28 +4,25 @@ block vars
- bootstrap5PageStatus = 'disabled'
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container-custom-sm.mx-auto
.card
form(
data-ol-async-form,
name="passwordResetForm",
action="/user/password/set",
method="POST",
data-ol-hide-on-error="token-expired"
name='passwordResetForm'
data-ol-async-form
action='/user/password/set'
method='POST'
data-ol-hide-on-error='token-expired'
)
div(
hidden
data-ol-sent
)
div(hidden data-ol-sent)
h3.mt-0.mb-2 #{translate("password_updated")}
p.mb-4 #{translate("your_password_has_been_successfully_changed")}.
a(href='/login') #{translate("log_in_now")}
div(data-ol-not-sent)
h3.mt-0.mb-2 #{translate("reset_your_password")}
p(data-ol-hide-on-error-message="token-expired") #{translate("create_a_new_password_for_your_account")}.
+formMessages()
p(data-ol-hide-on-error-message='token-expired') #{translate("create_a_new_password_for_your_account")}.
+formMessages
+customFormMessage('password-contains-email', 'danger')
| #{translate('invalid_password_contains_email')}.
@@ -38,21 +35,30 @@ block content
+customFormMessage('token-expired', 'danger')
| #{translate('password_reset_token_expired')}
br
a(href="/user/password/reset")
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(name='_csrf' type='hidden' value=csrfToken)
input(
name='email'
type='text'
hidden
autocomplete='username'
value=email
)
.form-group
label(for='passwordField', data-ol-hide-on-error-message="token-expired") #{translate("new_password")}
input.form-control#passwordField(
type='password',
name='password',
placeholder=translate("enter_your_new_password"),
autocomplete="new-password",
autofocus,
required,
label(
for='passwordField'
data-ol-hide-on-error-message='token-expired'
) #{translate("new_password")}
input#passwordField.form-control(
name='password'
type='password'
placeholder=translate('enter_your_new_password')
autocomplete='new-password'
autofocus
required
minlength=settings.passwordStrengthOptions.length.min
)
@@ -66,12 +72,8 @@ block content
| !{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")
input(name='passwordResetToken' type='hidden' 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-4.ps-4
li #{translate('is_longer_than_n_characters', {n: settings.passwordStrengthOptions.length.min})}
@@ -79,11 +81,11 @@ block content
li #{translate('is_not_used_on_any_other_website')}
.actions
button.btn.btn-primary.w-100(
type='submit',
type='submit'
data-ol-disabled-inflight
aria-label=translate('set_new_password')
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate('set_new_password')}
span(hidden data-ol-inflight="pending")
span(hidden data-ol-inflight='pending')
| #{translate('set_new_password')}…

View File

@@ -2,38 +2,65 @@ extends ../layout-react
block entrypointVar
- entrypoint = 'pages/user/settings'
block vars
- isWebsiteRedesign = true
block append meta
meta(name="ol-hasPassword" data-type="boolean" content=hasPassword)
meta(name="ol-shouldAllowEditingDetails" data-type="boolean" content=shouldAllowEditingDetails)
meta(name="ol-oauthProviders", data-type="json", content=oauthProviders)
meta(name="ol-institutionLinked", data-type="json", content=institutionLinked)
meta(name="ol-samlError", data-type="json", content=samlError)
meta(name="ol-institutionEmailNonCanonical", content=institutionEmailNonCanonical)
meta(name='ol-hasPassword' data-type='boolean' content=hasPassword)
meta(
name='ol-shouldAllowEditingDetails'
data-type='boolean'
content=shouldAllowEditingDetails
)
meta(name='ol-oauthProviders' data-type='json' content=oauthProviders)
meta(name='ol-institutionLinked' data-type='json' content=institutionLinked)
meta(name='ol-samlError' data-type='json' content=samlError)
meta(
name='ol-institutionEmailNonCanonical'
content=institutionEmailNonCanonical
)
meta(name="ol-reconfirmedViaSAML", content=reconfirmedViaSAML)
meta(name="ol-reconfirmationRemoveEmail", content=reconfirmationRemoveEmail)
meta(name="ol-samlBeta", content=samlBeta)
meta(name="ol-ssoErrorMessage", content=ssoErrorMessage)
meta(name="ol-thirdPartyIds", data-type="json", content=thirdPartyIds || {})
meta(name="ol-passwordStrengthOptions", data-type="json", content=settings.passwordStrengthOptions || {})
meta(name="ol-isExternalAuthenticationSystemUsed" data-type="boolean" content=externalAuthenticationSystemUsed())
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-labsExperiments" data-type="json" content=labsExperiments)
meta(name="ol-dropbox" data-type="json" content=dropbox)
meta(name="ol-github" data-type="json" content=github)
meta(name="ol-projectSyncSuccessMessage", content=projectSyncSuccessMessage)
meta(name="ol-personalAccessTokens", data-type="json" content=personalAccessTokens)
meta(name="ol-emailAddressLimit", data-type="json", content=emailAddressLimit)
meta(name="ol-currentManagedUserAdminEmail" data-type="string" content=currentManagedUserAdminEmail)
meta(name="ol-gitBridgeEnabled" data-type="boolean" content=gitBridgeEnabled)
meta(name="ol-isSaas" data-type="boolean" content=isSaas)
meta(name="ol-memberOfSSOEnabledGroups" data-type="json" content=memberOfSSOEnabledGroups)
meta(name="ol-capabilities" data-type="json" content=capabilities)
meta(name='ol-reconfirmedViaSAML' content=reconfirmedViaSAML)
meta(name='ol-reconfirmationRemoveEmail' content=reconfirmationRemoveEmail)
meta(name='ol-samlBeta' content=samlBeta)
meta(name='ol-ssoErrorMessage' content=ssoErrorMessage)
meta(name='ol-thirdPartyIds' data-type='json' content=thirdPartyIds || {})
meta(
name='ol-passwordStrengthOptions'
data-type='json'
content=settings.passwordStrengthOptions || {}
)
meta(
name='ol-isExternalAuthenticationSystemUsed'
data-type='boolean'
content=externalAuthenticationSystemUsed()
)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-labsExperiments' data-type='json' content=labsExperiments)
meta(name='ol-dropbox' data-type='json' content=dropbox)
meta(name='ol-github' data-type='json' content=github)
meta(name='ol-projectSyncSuccessMessage' content=projectSyncSuccessMessage)
meta(
name='ol-personalAccessTokens'
data-type='json'
content=personalAccessTokens
)
meta(name='ol-emailAddressLimit' data-type='json' content=emailAddressLimit)
meta(
name='ol-currentManagedUserAdminEmail'
data-type='string'
content=currentManagedUserAdminEmail
)
meta(name='ol-gitBridgeEnabled' data-type='boolean' content=gitBridgeEnabled)
meta(name='ol-isSaas' data-type='boolean' content=isSaas)
meta(
name='ol-memberOfSSOEnabledGroups'
data-type='json'
content=memberOfSSOEnabledGroups
)
meta(name='ol-capabilities' data-type='json' content=capabilities)
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
#settings-page-root

View File

@@ -4,10 +4,10 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/group-managers'
block append meta
meta(name="ol-user", data-type="json", content=user)
meta(name="ol-users", data-type="json", content=users)
meta(name="ol-groupId", data-type="string", content=groupId)
meta(name="ol-groupName", data-type="string", content=name)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-users' data-type='json' content=users)
meta(name='ol-groupId' data-type='string' content=groupId)
meta(name='ol-groupName' data-type='string' content=name)
block content
main.content.content-alt#subscription-manage-group-root
main#subscription-manage-group-root.content.content-alt

View File

@@ -2,18 +2,34 @@ extends ../layout-react
block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/group-members'
block append meta
meta(name="ol-user", data-type="json", content=user)
meta(name="ol-users", data-type="json", content=users)
meta(name="ol-groupId", data-type="string", content=groupId)
meta(name="ol-groupName", data-type="string", content=name)
meta(name="ol-groupSize", data-type="json", content=groupSize)
meta(name="ol-managedUsersActive", data-type="boolean", content=managedUsersActive)
meta(name="ol-isUserGroupManager", data-type="boolean", content=isUserGroupManager)
meta(name="ol-groupSSOActive", data-type="boolean", content=groupSSOActive)
meta(name="ol-canUseFlexibleLicensing", data-type="boolean", content=canUseFlexibleLicensing)
meta(name="ol-canUseAddSeatsFeature", data-type="boolean", content=canUseAddSeatsFeature)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-users' data-type='json' content=users)
meta(name='ol-groupId' data-type='string' content=groupId)
meta(name='ol-groupName' data-type='string' content=name)
meta(name='ol-groupSize' data-type='json' content=groupSize)
meta(
name='ol-managedUsersActive'
data-type='boolean'
content=managedUsersActive
)
meta(
name='ol-isUserGroupManager'
data-type='boolean'
content=isUserGroupManager
)
meta(name='ol-groupSSOActive' data-type='boolean' content=groupSSOActive)
meta(
name='ol-canUseFlexibleLicensing'
data-type='boolean'
content=canUseFlexibleLicensing
)
meta(
name='ol-canUseAddSeatsFeature'
data-type='boolean'
content=canUseAddSeatsFeature
)
block content
main.content.content-alt#subscription-manage-group-root
main#subscription-manage-group-root.content.content-alt

View File

@@ -4,10 +4,10 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/institution-managers'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-users", data-type="json", content=users)
meta(name="ol-groupId", data-type="string", content=groupId)
meta(name="ol-groupName", data-type="string", content=name)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-users' data-type='json' content=users)
meta(name='ol-groupId' data-type='string' content=groupId)
meta(name='ol-groupName' data-type='string' content=name)
block content
main.content.content-alt#subscription-manage-group-root
main#subscription-manage-group-root.content.content-alt

View File

@@ -4,20 +4,13 @@ block vars
- bootstrap5PageStatus = 'disabled'
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
.row
.col-md-10.col-md-offset-1
h3 #{entityName} "#{entityId}" does not exists in v2
form(
data-ol-regular-form
method='post',
action=''
)
input(name="_csrf", type="hidden", value=csrfToken)
button.btn.btn-primary(
type="submit",
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") Create #{entityName} in v2
span(hidden data-ol-inflight="pending") #{translate("creating")}…
form(data-ol-regular-form method='post' action='')
input(name='_csrf' type='hidden' value=csrfToken)
button.btn.btn-primary(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') Create #{entityName} in v2
span(hidden data-ol-inflight='pending') #{translate("creating")}…

View File

@@ -4,10 +4,10 @@ block entrypointVar
- entrypoint = 'pages/user/subscription/group-management/publisher-managers'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-users", data-type="json", content=users)
meta(name="ol-groupId", data-type="string", content=groupId)
meta(name="ol-groupName", data-type="string", content=name)
meta(name='ol-user' data-type='json' content=user)
meta(name='ol-users' data-type='json' content=users)
meta(name='ol-groupId' data-type='string' content=groupId)
meta(name='ol-groupName' data-type='string' content=name)
block content
main.content.content-alt#subscription-manage-group-root
main#subscription-manage-group-root.content.content-alt

View File

@@ -2,39 +2,43 @@ extends ../../../../app/views/layout-marketing
mixin launchpad-check(section)
div(data-ol-launchpad-check=section)
span(data-ol-inflight="pending")
span(data-ol-inflight='pending')
i.fa.fa-fw.fa-spinner.fa-spin
span &nbsp;#{translate('checking')}
span(hidden data-ol-inflight="idle")
div(data-ol-result="success")
span(hidden data-ol-inflight='idle')
div(data-ol-result='success')
i.fa.fa-check
span &nbsp;#{translate('ok')}
button.btn.btn-inline-link
span.text-danger &nbsp;#{translate('retry')}
div(hidden data-ol-result="error")
div(hidden data-ol-result='error')
i.fa.fa-exclamation
span &nbsp;#{translate('error')}
button.btn.btn-inline-link
span.text-danger &nbsp;#{translate('retry')}
div.alert.alert-danger
.alert.alert-danger
span(data-ol-error)
block entrypointVar
- entrypoint = 'modules/launchpad/pages/launchpad'
block vars
- metadata = metadata || {}
- bootstrap5PageStatus = 'disabled'
block append meta
meta(name="ol-adminUserExists" data-type="boolean" content=adminUserExists)
meta(name="ol-ideJsPath" content=buildJsPath('ide.js'))
meta(name='ol-adminUserExists' data-type='boolean' content=adminUserExists)
meta(name='ol-ideJsPath' content=buildJsPath('ide.js'))
block content
script(type="text/javascript", nonce=scriptNonce, src=(wsUrl || '/socket.io') + '/socket.io.js')
script(
type='text/javascript'
nonce=scriptNonce
src=(wsUrl || '/socket.io') + '/socket.io.js'
)
.content.content-alt#main-content
#main-content.content.content-alt
.container
.row
.col-md-8.col-md-offset-2
@@ -49,8 +53,6 @@ block content
<!-- wrapper -->
.row
.col-md-8.col-md-offset-2
<!-- create first admin form -->
if !adminUserExists
.row(data-ol-not-sent)
@@ -62,37 +64,34 @@ block content
form(
data-ol-async-form
data-ol-register-admin
action="/launchpad/register_admin"
method="POST"
action='/launchpad/register_admin'
method='POST'
)
input(name='_csrf', type='hidden', value=csrfToken)
+formMessages()
input(name='_csrf' type='hidden' value=csrfToken)
+formMessages
.form-group
label(for='email') #{translate("email")}
input.form-control(
type='email',
name='email',
placeholder="email@example.com"
autocomplete="username"
required,
autofocus="true"
name='email'
type='email'
placeholder='email@example.com'
autocomplete='username'
required
autofocus='true'
)
.form-group
label(for='password') #{translate("password")}
input.form-control#passwordField(
type='password',
name='password',
placeholder="********",
autocomplete="new-password"
required,
input#passwordField.form-control(
name='password'
type='password'
placeholder='********'
autocomplete='new-password'
required
)
.actions
button.btn-primary.btn(
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("register")}
span(hidden data-ol-inflight="pending") #{translate("registering")}…
button.btn-primary.btn(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("register")}
span(hidden data-ol-inflight='pending') #{translate("registering")}…
// Ldap Form
if authMethod === 'ldap'
@@ -103,28 +102,25 @@ block content
form(
data-ol-async-form
data-ol-register-admin
action="/launchpad/register_ldap_admin"
method="POST"
action='/launchpad/register_ldap_admin'
method='POST'
)
input(name='_csrf', type='hidden', value=csrfToken)
+formMessages()
input(name='_csrf' type='hidden' value=csrfToken)
+formMessages
.form-group
label(for='email') #{translate("email")}
input.form-control(
type='email',
name='email',
placeholder="email@example.com"
autocomplete="username"
required,
autofocus="true"
name='email'
type='email'
placeholder='email@example.com'
autocomplete='username'
required
autofocus='true'
)
.actions
button.btn-primary.btn(
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("register")}
span(hidden data-ol-inflight="pending") #{translate("registering")}…
button.btn-primary.btn(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("register")}
span(hidden data-ol-inflight='pending') #{translate("registering")}…
// Saml Form
if authMethod === 'saml'
@@ -135,28 +131,25 @@ block content
form(
data-ol-async-form
data-ol-register-admin
action="/launchpad/register_saml_admin"
method="POST"
action='/launchpad/register_saml_admin'
method='POST'
)
input(name='_csrf', type='hidden', value=csrfToken)
+formMessages()
input(name='_csrf' type='hidden' value=csrfToken)
+formMessages
.form-group
label(for='email') #{translate("email")}
input.form-control(
type='email',
name='email',
placeholder="email@example.com"
autocomplete="username"
required,
autofocus="true"
name='email'
type='email'
placeholder='email@example.com'
autocomplete='username'
required
autofocus='true'
)
.actions
button.btn-primary.btn(
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("register")}
span(hidden data-ol-inflight="pending") #{translate("registering")}…
button.btn-primary.btn(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("register")}
span(hidden data-ol-inflight='pending') #{translate("registering")}…
br
@@ -164,7 +157,6 @@ block content
if adminUserExists
.row
.col-md-12.status-indicators
h2 #{translate('status_checks')}
<!-- websocket -->
@@ -185,42 +177,31 @@ block content
h3 #{translate('send_test_email')}
form.form(
data-ol-async-form
action="/launchpad/send_test_email"
method="POST"
action='/launchpad/send_test_email'
method='POST'
)
.form-group
label(for="email") Email
input.form-control(
type="text"
id="email"
name="email"
required
)
button.btn-primary.btn(
type='submit'
data-ol-disabled-inflight
)
span(data-ol-inflight="idle") #{translate("send")}
span(hidden data-ol-inflight="pending") #{translate("sending")}…
label(for='email') Email
input.form-control(name='email' type='text' id='email' required)
button.btn-primary.btn(type='submit' data-ol-disabled-inflight)
span(data-ol-inflight='idle') #{translate("send")}
span(hidden data-ol-inflight='pending') #{translate("sending")}…
p
+formMessages()
+formMessages
<!-- break -->
hr.thin
<!-- Go to app -->
.row
.col-md-12
.text-center
br
p
a(href="/admin").btn.btn-info
a.btn.btn-info(href='/admin')
| Go To Admin Panel
| &nbsp;
a(href="/project").btn.btn-primary
a.btn.btn-primary(href='/project')
| Start Using #{settings.appName}
br

View File

@@ -6,14 +6,14 @@ block vars
include ../../../../../app/views/_mixins/material_symbol
block content
main.content.content-alt#main-content
main#main-content.content.content-alt
.container
div.col-lg-6.col-xl-4.m-auto
.col-lg-6.col-xl-4.m-auto
.notification-list
.notification.notification-type-success(aria-live="off" role="alert")
.notification.notification-type-success(aria-live='off' role='alert')
.notification-content-and-cta
.notification-icon
+material-symbol("check_circle")
+material-symbol('check_circle')
.notification-content
p
| #{translate("nearly_activated")}
@@ -21,12 +21,12 @@ block content
h1.h3 #{translate("please_set_a_password")}
form(
name='activationForm'
data-ol-async-form
name="activationForm",
action="/user/password/set",
method="POST",
action='/user/password/set'
method='POST'
)
+formMessages()
+formMessages
+customFormMessage('token-expired', 'danger')
| #{translate("activation_token_expired")}
@@ -34,43 +34,39 @@ block content
+customFormMessage('invalid-password', 'danger')
| #{translate('invalid_password')}
input(name='_csrf', type='hidden', value=csrfToken)
input(
type="hidden",
name="passwordResetToken",
value=token
)
input(name='_csrf' type='hidden' value=csrfToken)
input(name='passwordResetToken' type='hidden' value=token)
.form-group
label(for='emailField') #{translate("email")}
input.form-control#emailField(
aria-label="email",
type='email',
name='email',
placeholder="email@example.com",
autocomplete="username"
input#emailField.form-control(
name='email'
aria-label='email'
type='email'
placeholder='email@example.com'
autocomplete='username'
value=email
required,
required
disabled
)
.form-group
label(for='passwordField') #{translate("password")}
input.form-control#passwordField(
type='password',
name='password',
placeholder="********",
autocomplete="new-password",
autofocus,
required,
input#passwordField.form-control(
name='password'
type='password'
placeholder='********'
autocomplete='new-password'
autofocus
required
minlength=settings.passwordStrengthOptions.length.min
)
.actions
button.btn.btn-primary(
type='submit',
type='submit'
data-ol-disabled-inflight
aria-label=translate('activate')
)
span(data-ol-inflight="idle")
span(data-ol-inflight='idle')
| #{translate('activate')}
span(hidden data-ol-inflight="pending")
span(hidden data-ol-inflight='pending')
| #{translate('activating')}…

View File

@@ -4,9 +4,9 @@ block entrypointVar
- entrypoint = 'modules/user-activate/pages/user-activate-page'
block append meta
meta(name="ol-user" data-type="json" content=user)
meta(name='ol-user' data-type='json' content=user)
block content
.content.content-alt#main-content
#main-content.content.content-alt
.container
#user-activate-register-container

View File

@@ -28,6 +28,8 @@
"format:fix": "prettier --write $PWD/'**/*.{js,jsx,mjs,ts,tsx,json}'",
"format:styles": "prettier --list-different $PWD/'**/*.{css,less,scss}'",
"format:styles:fix": "prettier --write $PWD/'**/*.{css,less,scss}'",
"format:pug": "prettier --list-different $PWD/'**/*.pug'",
"format:pug:fix": "prettier --write $PWD/'**/*.pug'",
"lint": "eslint --max-warnings 0 --format unix --ext .js,.jsx,.mjs,.ts,.tsx .",
"lint:fix": "eslint --fix --ext .js,.jsx,.mjs,.ts,.tsx .",
"lint:styles": "stylelint '**/*.scss'",
@@ -209,6 +211,7 @@
"@pollyjs/adapter-node-http": "^6.0.6",
"@pollyjs/core": "^6.0.6",
"@pollyjs/persister-fs": "^6.0.6",
"@prettier/plugin-pug": "^3.4.0",
"@replit/codemirror-emacs": "overleaf/codemirror-emacs#4394c03858f27053f8768258e9493866e06e938e",
"@replit/codemirror-indentation-markers": "overleaf/codemirror-indentation-markers#78264032eb286bc47871569ae87bff5ca1c6c161",
"@replit/codemirror-vim": "overleaf/codemirror-vim#1bef138382d948018f3f9b8a4d7a70ab61774e4b",