first commit
This commit is contained in:
5
services/web/app/views/_cookie_banner.pug
Normal file
5
services/web/app/views/_cookie_banner.pug
Normal file
@@ -0,0 +1,5 @@
|
||||
.cookie-banner.hidden-print.hidden
|
||||
.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
|
26
services/web/app/views/_customer_io.pug
Normal file
26
services/web/app/views/_customer_io.pug
Normal file
@@ -0,0 +1,26 @@
|
||||
if(customerIoEnabled && ExposedSettings.cioWriteKey && ExposedSettings.cioSiteId)
|
||||
script(type="text/javascript", id="cio-loader", nonce=scriptNonce, data-cio-write-key=ExposedSettings.cioWriteKey, data-cio-site-id=ExposedSettings.cioSiteId, data-session-analytics-id=getSessionAnalyticsId(), data-user-id=getLoggedInUserId()).
|
||||
var cioSettings = document.querySelector('#cio-loader').dataset;
|
||||
var analyticsId = cioSettings.sessionAnalyticsId;
|
||||
var siteId = cioSettings.cioSiteId;
|
||||
var writeKey = cioSettings.cioWriteKey;
|
||||
var userId = cioSettings.userId;
|
||||
|
||||
!function(){var i="cioanalytics", analytics=(window[i]=window[i]||[]);if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.setAttribute('data-global-customerio-analytics-key', i);t.src="https://cdp.customer.io/v1/analytics-js/snippet/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._writeKey=key;analytics._loadOptions=e};analytics.SNIPPET_VERSION="4.15.3";
|
||||
analytics.load(
|
||||
writeKey,
|
||||
{
|
||||
disableClientPersistence: true,
|
||||
"integrations": {
|
||||
"Customer.io In-App Plugin": {
|
||||
siteId
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
if (analyticsId) {
|
||||
analytics.setAnonymousId(analyticsId);
|
||||
};
|
||||
// If userId is undefined, identify sends only the anonymousId (aka analyticsId)
|
||||
analytics.identify(userId);
|
||||
}}();
|
58
services/web/app/views/_google_analytics.pug
Normal file
58
services/web/app/views/_google_analytics.pug
Normal file
@@ -0,0 +1,58 @@
|
||||
if (typeof(ExposedSettings.gaTokenV4) != "undefined" || typeof(ExposedSettings.gaToken) != "undefined")
|
||||
script(type="text/javascript", nonce=scriptNonce, id="ga-loader" data-ga-token=ExposedSettings.gaToken data-ga-token-v4=ExposedSettings.gaTokenV4 data-cookie-domain=ExposedSettings.cookieDomain data-session-analytics-id=getSessionAnalyticsId()).
|
||||
var gaSettings = document.querySelector('#ga-loader').dataset;
|
||||
var gaid = gaSettings.gaTokenV4;
|
||||
var gaToken = gaSettings.gaToken;
|
||||
var cookieDomain = gaSettings.cookieDomain;
|
||||
var sessionAnalyticsId = gaSettings.sessionAnalyticsId;
|
||||
if(gaid) {
|
||||
var additionalGaConfig = sessionAnalyticsId ? { 'user_id': sessionAnalyticsId } : {};
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
gtag('config', gaid, { 'anonymize_ip': true, ...additionalGaConfig });
|
||||
}
|
||||
if (gaToken) {
|
||||
window.ga = window.ga || function () {
|
||||
(window.ga.q = window.ga.q || []).push(arguments);
|
||||
}, window.ga.l = 1 * new Date();
|
||||
}
|
||||
var loadGA = window.olLoadGA = function() {
|
||||
if (gaid) {
|
||||
var s = document.createElement('script');
|
||||
s.setAttribute('async', 'async');
|
||||
s.setAttribute('src', 'https://www.googletagmanager.com/gtag/js?id=' + gaid);
|
||||
document.querySelector('head').append(s);
|
||||
}
|
||||
if (gaToken) {
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
ga('create', gaToken, cookieDomain.replace(/^\./, ""));
|
||||
ga('set', 'anonymizeIp', true);
|
||||
if (sessionAnalyticsId) {
|
||||
ga('set', 'userId', sessionAnalyticsId);
|
||||
}
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
};
|
||||
// Check if consent given (features/cookie-banner)
|
||||
var oaCookie = document.cookie.split('; ').find(function(cookie) {
|
||||
return cookie.startsWith('oa=');
|
||||
});
|
||||
if(oaCookie) {
|
||||
var oaCookieValue = oaCookie.split('=')[1];
|
||||
if(oaCookieValue === '1') {
|
||||
loadGA();
|
||||
}
|
||||
}
|
||||
|
||||
if typeof(ExposedSettings.gaTokenV4) === "undefined"
|
||||
script(type="text/javascript", nonce=scriptNonce).
|
||||
window.gtag = function() { console.log("would send to GA4", arguments) };
|
||||
if typeof(ExposedSettings.gaToken) === "undefined"
|
||||
script(type="text/javascript", nonce=scriptNonce).
|
||||
window.ga = function() { console.log("would send to GA", arguments) };
|
123
services/web/app/views/_metadata.pug
Normal file
123
services/web/app/views/_metadata.pug
Normal file
@@ -0,0 +1,123 @@
|
||||
|
||||
//- 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"))
|
||||
else
|
||||
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))
|
||||
|
||||
//- 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"))
|
||||
|
||||
//- Image
|
||||
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)
|
||||
//- 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)
|
||||
//- 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'))
|
||||
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')
|
||||
|
||||
//- Keywords
|
||||
if (metadata && metadata.keywords)
|
||||
meta(name="keywords" content=metadata.keywords)
|
||||
|
||||
//- Misc
|
||||
meta(itemprop="name", content=settings.appName + ", the Online LaTeX Editor")
|
||||
|
||||
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)
|
||||
else
|
||||
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)
|
||||
//- the default image for Overleaf
|
||||
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')
|
||||
|
||||
//- 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 (metadata && metadata.openGraphDescription)
|
||||
meta(property="og:description", content=metadata.openGraphDescription)
|
||||
else
|
||||
meta(property="og:description", content=translate("site_description"))
|
||||
|
||||
if (metadata && metadata.openGraphImage && metadata.openGraphImage.fields)
|
||||
//- from the CMS
|
||||
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'))
|
||||
else
|
||||
//- the default image for Overleaf Community Edition/Server Pro
|
||||
meta(property="og:image", content='/apple-touch-icon.png')
|
||||
|
||||
if (metadata && metadata.openGraphType)
|
||||
meta(property="og:type", metadata.openGraphType)
|
||||
else
|
||||
meta(property="og:type", content="website")
|
||||
|
||||
if (metadata && metadata.openGraphVideo)
|
||||
//- from the CMS
|
||||
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")
|
||||
|
||||
//- Noindex
|
||||
if settings.robotsNoindex
|
||||
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")
|
||||
|
||||
//- Canonical Tag for SEO
|
||||
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")
|
4
services/web/app/views/_mixins/back_to_btns.pug
Normal file
4
services/web/app/views/_mixins/back_to_btns.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
mixin back-to-btns(settingsAnchor)
|
||||
a.btn.btn-secondary.text-capitalize(href=`/user/settings${settingsAnchor ? '#' + settingsAnchor : '' }`) #{translate('back_to_account_settings')}
|
||||
|
|
||||
a.btn.btn-secondary.text-capitalize(href='/project') #{translate('back_to_your_projects')}
|
25
services/web/app/views/_mixins/begin_now_card.pug
Normal file
25
services/web/app/views/_mixins/begin_now_card.pug
Normal file
@@ -0,0 +1,25 @@
|
||||
mixin begin_now_card()
|
||||
- var registerURL = '/register'
|
||||
- var plansURL = '/user/subscription/plans'
|
||||
- var isUserLoggedIn = !!getSessionUser()
|
||||
|
||||
.begin-now-card
|
||||
div.card.card-pattern
|
||||
.card-body
|
||||
p.dm-mono
|
||||
span.font-size-display-xs
|
||||
span.text-purple-bright \begin
|
||||
wbr
|
||||
span.text-green-bright {
|
||||
span now
|
||||
span.text-green-bright }
|
||||
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.card-link(
|
||||
class = isUserLoggedIn ? 'btn-primary' : 'btn-secondary'
|
||||
href=plansURL
|
||||
) #{translate("explore_all_plans")}
|
10
services/web/app/views/_mixins/bookmarkable_tabset.pug
Normal file
10
services/web/app/views/_mixins/bookmarkable_tabset.pug
Normal file
@@ -0,0 +1,10 @@
|
||||
mixin bookmarkable-tabset-header(id, title, active)
|
||||
li(role="presentation")
|
||||
a.nav-link(
|
||||
href='#' + id
|
||||
class=(active ? 'active' : '')
|
||||
aria-controls=id
|
||||
role="tab"
|
||||
data-toggle="tab"
|
||||
data-ol-bookmarkable-tab
|
||||
) #{title}
|
3
services/web/app/views/_mixins/bootstrap_js.pug
Normal file
3
services/web/app/views/_mixins/bootstrap_js.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
mixin bootstrap-js(bootstrapVersion)
|
||||
each file in (entrypointScripts(bootstrapVersion === 5 ? 'bootstrap-5' : 'bootstrap-3'))
|
||||
script(type="text/javascript", nonce=scriptNonce, src=file)
|
5
services/web/app/views/_mixins/eyebrow.pug
Normal file
5
services/web/app/views/_mixins/eyebrow.pug
Normal file
@@ -0,0 +1,5 @@
|
||||
mixin eyebrow(text)
|
||||
span.eyebrow-text
|
||||
span(aria-hidden="true") {
|
||||
span #{text}
|
||||
span(aria-hidden="true") }
|
30
services/web/app/views/_mixins/faq_search-marketing.pug
Normal file
30
services/web/app/views/_mixins/faq_search-marketing.pug
Normal file
@@ -0,0 +1,30 @@
|
||||
mixin faq_search-marketing(headerText, headerClass)
|
||||
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-group.has-feedback.has-feedback-left
|
||||
.col-sm-12
|
||||
input.form-control(type='text', placeholder="Search help library…")
|
||||
i.fa.fa-search.form-control-feedback-left(aria-hidden="true")
|
||||
i.fa.fa-times.form-control-feedback(
|
||||
style="cursor: pointer;",
|
||||
hidden
|
||||
data-ol-clear-search
|
||||
aria-hidden="true"
|
||||
)
|
||||
button.sr-only(
|
||||
type="button"
|
||||
hidden
|
||||
data-ol-clear-search
|
||||
aria-label=translate('clear_search')
|
||||
)
|
||||
|
||||
.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)
|
||||
div(data-ol-search-results)
|
||||
.row-spaced-small.search-result.card.card-thin(hidden data-ol-search-no-results)
|
||||
p #{translate("no_search_results")}
|
6
services/web/app/views/_mixins/foot_scripts.pug
Normal file
6
services/web/app/views/_mixins/foot_scripts.pug
Normal file
@@ -0,0 +1,6 @@
|
||||
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)
|
91
services/web/app/views/_mixins/formMessages.pug
Normal file
91
services/web/app/views/_mixins/formMessages.pug
Normal file
@@ -0,0 +1,91 @@
|
||||
mixin formMessages()
|
||||
div(
|
||||
data-ol-form-messages='',
|
||||
role="alert"
|
||||
)
|
||||
|
||||
mixin formMessagesNewStyle()
|
||||
div(
|
||||
data-ol-form-messages-new-style='',
|
||||
role="alert"
|
||||
)
|
||||
|
||||
mixin customFormMessage(key, kind)
|
||||
if kind === 'success'
|
||||
div.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"
|
||||
)
|
||||
block
|
||||
else
|
||||
div.alert.alert-warning(
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
block
|
||||
|
||||
mixin customFormMessageNewStyle(key, kind)
|
||||
if kind === 'success'
|
||||
div.notification.notification-type-success(
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
div.notification-icon
|
||||
span.material-symbols(aria-hidden="true") check_circle
|
||||
div.notification-content.text-left
|
||||
block
|
||||
else if kind === 'danger'
|
||||
div.notification.notification-type-error(
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
div.notification-icon
|
||||
span.material-symbols(aria-hidden="true") error
|
||||
div.notification-content.text-left
|
||||
block
|
||||
else
|
||||
div.notification.notification-type-warning(
|
||||
hidden,
|
||||
data-ol-custom-form-message=key,
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
div.notification-icon
|
||||
span.material-symbols(aria-hidden="true") warning
|
||||
div.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")
|
||||
div
|
||||
block
|
||||
|
||||
mixin customValidationMessageNewStyle(key)
|
||||
div.notification.notification-type-error(
|
||||
hidden,
|
||||
data-ol-custom-form-message=key
|
||||
)
|
||||
div.notification-icon
|
||||
span.material-symbols(aria-hidden="true") error
|
||||
div.notification-content.text-left.small
|
||||
block
|
123
services/web/app/views/_mixins/links.pug
Normal file
123
services/web/app/views/_mixins/links.pug
Normal file
@@ -0,0 +1,123 @@
|
||||
mixin linkAdvisors(linkText, linkClass, track)
|
||||
//- To Do: verify path
|
||||
- var gaCategory = track && track.category ? track.category : 'All'
|
||||
- var gaAction = track && track.action ? track.action : null
|
||||
- var gaLabel = track && track.label ? track.label : null
|
||||
- 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"
|
||||
class=linkClass ? linkClass : ''
|
||||
event-tracking-ga=gaCategory
|
||||
event-tracking=gaAction
|
||||
event-tracking-label=gaLabel
|
||||
event-tracking-trigger=trigger
|
||||
event-tracking-mb=mb
|
||||
event-segmentation=mbSegmentation
|
||||
)
|
||||
span #{linkText ? linkText : 'advisor programme'}
|
||||
|
||||
mixin linkBenefits(linkText, 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 : '')
|
||||
| #{linkText ? linkText : 'blog'}
|
||||
|
||||
mixin linkContact(linkText, linkClass)
|
||||
a(href=(settings.siteUrl ? settings.siteUrl : '') + "/contact" class=linkClass ? linkClass : '')
|
||||
| #{linkText ? linkText : 'contact'}
|
||||
|
||||
mixin linkDash(linkText, 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 : '')
|
||||
| #{linkText ? linkText : 'teaching toolkit'}
|
||||
|
||||
mixin linkInvite(linkText, linkClass, track)
|
||||
- var gaCategory = track && track.category ? track.category : 'All'
|
||||
- var gaAction = track && track.action ? track.action : null
|
||||
- var gaLabel = track && track.label ? track.label : null
|
||||
- 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="/user/bonus"
|
||||
class=linkClass ? linkClass : ''
|
||||
event-tracking-ga=gaCategory
|
||||
event-tracking=gaAction
|
||||
event-tracking-label=gaLabel
|
||||
event-tracking-trigger=trigger
|
||||
event-tracking-mb=mb
|
||||
event-segmentation=mbSegmentation
|
||||
)
|
||||
span #{linkText ? linkText : 'invite your friends'}
|
||||
|
||||
mixin linkPlansAndPricing(linkText, linkClass)
|
||||
a(href="/user/subscription/plans" class=linkClass ? linkClass : '')
|
||||
| #{linkText ? linkText : 'plans and pricing'}
|
||||
|
||||
mixin linkPrintNewTab(linkText, linkClass, icon, track)
|
||||
- var gaCategory = track && track.category ? track.category : null
|
||||
- var gaAction = track && track.action ? track.action : null
|
||||
- var gaLabel = track && track.label ? track.label : null
|
||||
- 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='?media=print'
|
||||
class=linkClass ? linkClass : ''
|
||||
event-tracking-ga=gaCategory
|
||||
event-tracking=gaAction
|
||||
event-tracking-label=gaLabel
|
||||
event-tracking-trigger=trigger
|
||||
event-tracking-mb=mb
|
||||
event-segmentation=mbSegmentation
|
||||
target="_BLANK",
|
||||
rel="noopener noreferrer"
|
||||
)
|
||||
if icon
|
||||
i(class="fa fa-print")
|
||||
|
|
||||
span #{linkText ? linkText : 'print'}
|
||||
|
||||
mixin linkSignIn(linkText, linkClass, redirect)
|
||||
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 : '')
|
||||
| #{linkText ? linkText : 'sign up'}
|
||||
|
||||
mixin linkTweet(linkText, linkClass, tweetText, track)
|
||||
//- twitter-share-button is required by twitter
|
||||
- var gaCategory = track && track.category ? track.category : 'All'
|
||||
- var gaAction = track && track.action ? track.action : null
|
||||
- var gaLabel = track && track.label ? track.label : null
|
||||
- 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
|
||||
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"
|
||||
) #{linkText ? linkText : 'tweet'}
|
||||
|
||||
mixin linkUniversities(linkText, 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)
|
||||
| #{text}
|
||||
i.material-symbols(aria-hidden="true") arrow_right_alt
|
23
services/web/app/views/_mixins/navbar.pug
Normal file
23
services/web/app/views/_mixins/navbar.pug
Normal file
@@ -0,0 +1,23 @@
|
||||
mixin nav-item
|
||||
li(role="none")&attributes(attributes)
|
||||
block
|
||||
|
||||
mixin nav-link
|
||||
a(role="menuitem").nav-link&attributes(attributes)
|
||||
block
|
||||
|
||||
mixin dropdown-menu
|
||||
ul(role="menu").dropdown-menu&attributes(attributes)
|
||||
block
|
||||
|
||||
mixin dropdown-menu-item
|
||||
li(role="none")
|
||||
block
|
||||
|
||||
mixin dropdown-menu-link-item
|
||||
+dropdown-menu-item
|
||||
a(role="menuitem").dropdown-item&attributes(attributes)
|
||||
block
|
||||
|
||||
mixin dropdown-menu-divider
|
||||
li(role="separator").dropdown-divider.d-none.d-lg-block
|
42
services/web/app/views/_mixins/notification.pug
Normal file
42
services/web/app/views/_mixins/notification.pug
Normal file
@@ -0,0 +1,42 @@
|
||||
//- to be kept in sync with frontend/js/shared/components/notification.tsx
|
||||
|
||||
mixin notificationIcon(type)
|
||||
if type === 'info'
|
||||
span.material-symbols(aria-hidden="true") info
|
||||
else if type === 'success'
|
||||
span.material-symbols(aria-hidden="true") check_circle
|
||||
else if type === 'error'
|
||||
span.material-symbols(aria-hidden="true") error
|
||||
else if type === 'warning'
|
||||
span.material-symbols(aria-hidden="true") 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
|
||||
)
|
||||
.notification-icon
|
||||
+notificationIcon(type)
|
||||
.notification-content-and-cta
|
||||
.notification-content
|
||||
if title
|
||||
p
|
||||
b #{title}
|
||||
| !{content}
|
||||
//- TODO: handle action
|
||||
//- if action
|
||||
//- .notification-cta
|
||||
if disclaimer
|
||||
.notification-disclaimer #{disclaimer}
|
||||
//- TODO: handle dismissible notifications
|
||||
//- TODO: handle onDismiss
|
||||
//- if isDismissible
|
||||
//- .notification-close-btn
|
||||
//- button(aria-label=translate('close'))
|
||||
//- span.material-symbols(aria-hidden="true") close
|
86
services/web/app/views/_mixins/pagination.pug
Normal file
86
services/web/app/views/_mixins/pagination.pug
Normal file
@@ -0,0 +1,86 @@
|
||||
mixin pagination(pages, page_path, max_btns)
|
||||
//- @param pages.current_page the current page viewed
|
||||
//- @param pages.total_pages previously calculated,
|
||||
//- based on total entries and entries per page
|
||||
//- @param page_path the relative path, minus a trailing slash and page param
|
||||
//- @param max_btns max number of buttons on either side of the current page
|
||||
//- button and excludes first, prev, next, last
|
||||
|
||||
if pages && pages.current_page && pages.total_pages && pages.total_pages > 1
|
||||
- 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/"
|
||||
|
||||
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") <<
|
||||
|
|
||||
| First
|
||||
li
|
||||
a(
|
||||
aria-label=translate("go_to_previous_page")
|
||||
href=full_page_path + (parseInt(pages.current_page, 10) - 1)
|
||||
rel="prev"
|
||||
)
|
||||
span(aria-hidden="true") <
|
||||
|
|
||||
| Prev
|
||||
|
||||
if pages.current_page - max_btns > 1
|
||||
li(aria-hidden="true")
|
||||
span …
|
||||
|
||||
while prev_page < pages.current_page
|
||||
li
|
||||
a(
|
||||
aria-label=translate("go_to_page_x", {page: prev_page})
|
||||
href=full_page_path + prev_page
|
||||
) #{prev_page}
|
||||
- prev_page++
|
||||
|
||||
li(class="active")
|
||||
span(
|
||||
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})
|
||||
href=full_page_path + next_page
|
||||
) #{next_page}
|
||||
- next_page++
|
||||
- next_index++
|
||||
|
||||
if next_page <= pages.total_pages
|
||||
li.ellipses(aria-hidden="true")
|
||||
span …
|
||||
|
||||
li
|
||||
a(
|
||||
aria-label=translate("go_to_next_page")
|
||||
href=full_page_path + (parseInt(pages.current_page, 10) + 1)
|
||||
rel="next"
|
||||
)
|
||||
| Next
|
||||
|
|
||||
span(aria-hidden="true") >
|
||||
|
||||
li
|
||||
a(
|
||||
aria-label=translate("go_to_last_page")
|
||||
href=full_page_path + pages.total_pages
|
||||
)
|
||||
| Last
|
||||
|
|
||||
span(aria-hidden="true") >>
|
4
services/web/app/views/_mixins/previous_page_link.pug
Normal file
4
services/web/app/views/_mixins/previous_page_link.pug
Normal file
@@ -0,0 +1,4 @@
|
||||
mixin previous-page-link(href, text)
|
||||
a.previous-page-link(href=href)
|
||||
i.material-symbols.material-symbols-rounded(aria-hidden="true") arrow_left_alt
|
||||
| #{text}
|
54
services/web/app/views/_mixins/quote.pug
Normal file
54
services/web/app/views/_mixins/quote.pug
Normal file
@@ -0,0 +1,54 @@
|
||||
mixin quoteLargeTextCentered(quote, person, position, affiliation, link, pictureUrl, pictureAltAttr)
|
||||
blockquote.quote-large-text-centered
|
||||
.quote !{quote}
|
||||
if pictureUrl
|
||||
.quote-img
|
||||
img(src=pictureUrl alt=pictureAltAttr)
|
||||
footer
|
||||
div.quote-person
|
||||
strong #{person}
|
||||
if person && position
|
||||
div #{position}
|
||||
if affiliation
|
||||
div #{affiliation}
|
||||
if link
|
||||
.quote-link !{link}
|
||||
|
||||
mixin quoteLeftGreenBorder({quote, person, position, affiliation, link})
|
||||
blockquote.quote-left-green-border
|
||||
.quote !{quote}
|
||||
footer
|
||||
| #{person}
|
||||
| #{position || affiliation ? ',' : ''}
|
||||
| #{position}
|
||||
| #{position && affiliation ? ' at ' : ''}
|
||||
| #{affiliation}
|
||||
if link
|
||||
.quote-link !{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, it’s 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, quotePerson)
|
||||
|
||||
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")
|
||||
.card-body
|
||||
+quoteLargeTextCentered(quote, quotePerson, quotePersonPosition, null, null, quotePersonImg, quotePerson)
|
||||
|
||||
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")
|
||||
.card-body
|
||||
+quoteLargeTextCentered(quote, quotePerson, quotePersonPosition, null, null, quotePersonImg, quotePerson)
|
2
services/web/app/views/_mixins/recaptcha.pug
Normal file
2
services/web/app/views/_mixins/recaptcha.pug
Normal file
@@ -0,0 +1,2 @@
|
||||
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'}}])}
|
@@ -0,0 +1,61 @@
|
||||
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()
|
||||
|
||||
.reconfirm-notification
|
||||
div(data-ol-not-sent style="width:100%;")
|
||||
i.fa.fa-warning
|
||||
|
||||
- var ssoEnabled = userEmail.affiliation && userEmail.affiliation.institution && userEmail.affiliation.institution.ssoEnabled
|
||||
if ssoEnabled
|
||||
- var institutionId = userEmail.affiliation && userEmail.affiliation.institution && userEmail.affiliation.institution.id
|
||||
a.btn-reconfirm.btn.btn-sm.btn-info(
|
||||
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")}…
|
||||
|
||||
else
|
||||
button.btn-reconfirm.btn.btn-sm.btn-info(
|
||||
type="submit"
|
||||
data-ol-disabled-inflight
|
||||
)
|
||||
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'])}
|
||||
|
||||
if location == '/user/settings'
|
||||
| !{translate('please_reconfirm_institutional_email', {}, [{ name: 'span' }])}
|
||||
if userEmail.default
|
||||
span #{translate('need_to_add_new_primary_before_remove')}
|
||||
else
|
||||
| !{translate("please_reconfirm_institutional_email", {}, [{name: 'a', attrs: {href: '/user/settings?remove=' + userEmail.email}}])}
|
||||
|
||||
|
|
||||
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'])}
|
||||
|
|
||||
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%;")
|
||||
//- extra div for flex styling
|
||||
| !{translate("your_affiliation_is_confirmed", {institutionName: userEmail.affiliation.institution.name}, ['strong'])}
|
||||
|
|
||||
| #{translate('thank_you_exclamation')}
|
3
services/web/app/views/_mixins/terms_of_service.pug
Normal file
3
services/web/app/views/_mixins/terms_of_service.pug
Normal file
@@ -0,0 +1,3 @@
|
||||
mixin termsOfServiceAgreement
|
||||
div.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'}}])}
|
102
services/web/app/views/admin/index.pug
Normal file
102
services/web/app/views/admin/index.pug
Normal file
@@ -0,0 +1,102 @@
|
||||
extends ../layout-marketing
|
||||
include ../_mixins/bookmarkable_tabset
|
||||
|
||||
block content
|
||||
.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-sm-12
|
||||
.card
|
||||
.card-body
|
||||
.page-header
|
||||
h1 Admin Panel
|
||||
.ol-tabs(data-ol-bookmarkable-tabset)
|
||||
.nav-tabs-container
|
||||
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')
|
||||
if hasFeature('saas')
|
||||
+bookmarkable-tabset-header('tpds', 'TPDS/Dropbox Management')
|
||||
|
||||
.tab-content
|
||||
.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-group
|
||||
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
|
||||
|
||||
.tab-pane(
|
||||
role="tabpanel"
|
||||
id='open-sockets'
|
||||
)
|
||||
.row-spaced
|
||||
ul
|
||||
each agents, url in openSockets
|
||||
li #{url} - total : #{agents.length}
|
||||
ul
|
||||
each agent in agents
|
||||
li #{agent}
|
||||
|
||||
.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
|
||||
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
|
||||
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
|
||||
p.small Will reopen the editor after closing.
|
||||
|
||||
if hasFeature('saas')
|
||||
.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-group
|
||||
label.form-label(for='project_id') project_id
|
||||
input.form-control(type='text', name='project_id', 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-group
|
||||
label.form-label(for='user_id') user_id
|
||||
input.form-control(type='text', name='user_id', placeholder='user_id', required)
|
||||
.form-group
|
||||
button.btn-primary.btn(type='submit') Poll
|
75
services/web/app/views/beta_program/opt_in.pug
Normal file
75
services/web/app/views/beta_program/opt_in.pug
Normal file
@@ -0,0 +1,75 @@
|
||||
extends ../layout-marketing
|
||||
include ../_mixins/back_to_btns
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container.beta-opt-in-wrapper
|
||||
.row
|
||||
.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
|
||||
.card
|
||||
.page-header
|
||||
h1
|
||||
| #{translate("sharelatex_beta_program")}
|
||||
.beta-opt-in
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-12
|
||||
if user.betaProgram
|
||||
p.text-centered
|
||||
strong #{translate("beta_program_already_participating")}.
|
||||
p !{translate("thank_you_for_being_part_of_our_beta_program", {}, ['strong'])}.
|
||||
else
|
||||
p.text-centered
|
||||
strong #{translate("beta_program_not_participating")}.
|
||||
p !{translate("beta_program_benefits", {}, ['strong'])}
|
||||
|
||||
p #[strong How it works:]
|
||||
ul
|
||||
li #{translate("beta_program_badge_description")} #[span(aria-label=translate("beta_feature_badge") role="img").beta-badge]
|
||||
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'])}.
|
||||
li !{translate("you_can_opt_in_and_out_of_the_program_at_any_time_on_this_page", {}, ['strong'])}.
|
||||
p !{translate("note_features_under_development", {}, ['strong'])}.
|
||||
|
||||
.row.text-centered
|
||||
.col-md-12
|
||||
if user.betaProgram
|
||||
form(
|
||||
data-ol-regular-form
|
||||
method="post"
|
||||
action="/beta/opt-out"
|
||||
novalidate
|
||||
)
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
.form-group
|
||||
a(
|
||||
href="https://forms.gle/CFEsmvZQTAwHCd3X9"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
).btn.btn-primary.btn-lg #{translate("give_feedback")}
|
||||
.form-group
|
||||
button.btn.btn-secondary-info.btn-secondary.btn-sm(
|
||||
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")}…
|
||||
else
|
||||
form(
|
||||
data-ol-regular-form
|
||||
method="post",
|
||||
action="/beta/opt-in"
|
||||
)
|
||||
input(type="hidden", name="_csrf", 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")}…
|
||||
.page-separator
|
||||
+back-to-btns()
|
31
services/web/app/views/general/400.pug
Normal file
31
services/web/app/views/general/400.pug
Normal file
@@ -0,0 +1,31 @@
|
||||
extends ../layout/layout-no-js
|
||||
|
||||
block vars
|
||||
- metadata = { title: 'Something went wrong' }
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block body
|
||||
body.full-height
|
||||
main.content.content-alt.full-height#main-content
|
||||
.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)
|
||||
|
|
||||
| The error is:
|
||||
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}
|
||||
| .
|
||||
p.error-actions
|
||||
a.error-btn(href="javascript:history.back()") Back
|
||||
|
|
||||
a.btn.btn-secondary(href="/") Home
|
14
services/web/app/views/general/404.pug
Normal file
14
services/web/app/views/general/404.pug
Normal file
@@ -0,0 +1,14 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.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
|
24
services/web/app/views/general/500.pug
Normal file
24
services/web/app/views/general/500.pug
Normal file
@@ -0,0 +1,24 @@
|
||||
extends ../layout/layout-no-js
|
||||
|
||||
block vars
|
||||
- metadata = { title: 'Something went wrong' }
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block body
|
||||
body.full-height
|
||||
main.content.content-alt.full-height#main-content
|
||||
.container.full-height
|
||||
.error-container.full-height
|
||||
.error-details
|
||||
p.error-status Something went wrong, sorry.
|
||||
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}
|
||||
|
|
||||
| or contact us at
|
||||
|
|
||||
a(href="mailto:" + settings.adminEmail) #{settings.adminEmail}
|
||||
| .
|
||||
p.error-actions
|
||||
a.error-btn(href="/") Home
|
22
services/web/app/views/general/closed.pug
Normal file
22
services/web/app/views/general/closed.pug
Normal file
@@ -0,0 +1,22 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-8.col-md-offset-2.text-center
|
||||
.page-header
|
||||
h1 Maintenance
|
||||
p
|
||||
if settings.statusPageUrl
|
||||
| #{settings.appName} is currently down for maintenance.
|
||||
| Please check our #[a(href='https://' + settings.statusPageUrl) status page]
|
||||
| for updates.
|
||||
else
|
||||
| #{settings.appName} is currently down for maintenance.
|
||||
| We should be back within minutes, but if not, or you have
|
||||
| an urgent request, please contact us at
|
||||
| #{settings.adminEmail}
|
26
services/web/app/views/general/post-gateway.pug
Normal file
26
services/web/app/views/general/post-gateway.pug
Normal file
@@ -0,0 +1,26 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressSkipToContent = true
|
||||
- var suppressCookieBanner = true
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
.content.content-alt
|
||||
.container
|
||||
.row
|
||||
.col-md-6.col-md-offset-3
|
||||
.card
|
||||
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])
|
46
services/web/app/views/general/unsupported-browser.pug
Normal file
46
services/web/app/views/general/unsupported-browser.pug
Normal file
@@ -0,0 +1,46 @@
|
||||
extends ../layout/layout-no-js
|
||||
|
||||
block vars
|
||||
- metadata = { title: 'Unsupported browser' }
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block body
|
||||
body.full-height
|
||||
main.content.content-alt.full-height#main-content
|
||||
.container.full-height
|
||||
.error-container.full-height
|
||||
.error-details
|
||||
h1.error-status Unsupported Browser
|
||||
p.error-description
|
||||
| Sorry, we don't support your browser anymore. Please see below what browsers we support.
|
||||
br
|
||||
| If you think you're seeing this message in error,
|
||||
|
|
||||
a(href="mailto:" + settings.adminEmail) please let us know
|
||||
| .
|
||||
|
||||
if fromURL
|
||||
p
|
||||
| URL:
|
||||
|
|
||||
a(href=fromURL) #{fromURL}
|
||||
|
||||
hr
|
||||
|
||||
p
|
||||
| Overleaf officially supports versions of Chrome, Firefox, Safari and Microsoft Edge released in the last 12 months.
|
||||
br
|
||||
| Firefox ESR is also supported for 12 months.
|
||||
p
|
||||
| Support for beta or developer-preview browser versions cannot be guaranteed. Please
|
||||
|
|
||||
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
|
||||
strong Overleaf has stopped supporting Internet Explorer as of April 26, 2021, and access is now blocked.
|
||||
p
|
||||
| If you cannot upgrade to one of the supported browsers,
|
||||
|
|
||||
a(href="mailto:" + settings.adminEmail) please let us know
|
||||
| .
|
112
services/web/app/views/layout-base.pug
Normal file
112
services/web/app/views/layout-base.pug
Normal file
@@ -0,0 +1,112 @@
|
||||
include ./_mixins/foot_scripts
|
||||
|
||||
doctype html
|
||||
html(
|
||||
lang=(currentLngCode || 'en')
|
||||
class=(fixedSizeDocument ? 'fixed-size-document' : undefined)
|
||||
)
|
||||
- metadata = metadata || {}
|
||||
- let bootstrap5PageStatus = 'enabled' // One of 'disabled' and 'enabled'
|
||||
- let bootstrap5PageSplitTest = '' // Limits Bootstrap 5 usage on this page to users with an assignment of "enabled" for the specified split test. If left empty and bootstrap5PageStatus is "enabled", the page always uses Bootstrap 5.
|
||||
- let isWebsiteRedesign = false
|
||||
- let isApplicationPage = false
|
||||
- let enableIeeeBranding = true
|
||||
|
||||
block entrypointVar
|
||||
|
||||
block isApplicationPageVar
|
||||
|
||||
block vars
|
||||
|
||||
head
|
||||
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")
|
||||
block css
|
||||
each file in entrypointStyles(entrypoint)
|
||||
link(rel='stylesheet', href=file)
|
||||
|
||||
block _headLinks
|
||||
|
||||
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)
|
||||
|
||||
if (entrypoint !== 'marketing')
|
||||
link(rel="preload", href=buildJsPath(currentLngCode + "-json.js"), as="script", nonce=scriptNonce)
|
||||
|
||||
//- Scripts
|
||||
if (typeof suppressGoogleAnalytics == "undefined")
|
||||
include _google_analytics
|
||||
|
||||
block meta
|
||||
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-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
|
||||
})
|
||||
//- 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 || {})
|
||||
|
||||
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)
|
||||
each restriction in userRestrictions || []
|
||||
meta(name='ol-cannot-' + restriction data-type="boolean" content=true)
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
block foot-scripts
|
||||
+foot-scripts
|
||||
|
||||
include _customer_io
|
||||
|
||||
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) {
|
||||
//- Set query param, server will not set CDN url
|
||||
window.location.search += "&nocdn=true";
|
||||
}
|
||||
})
|
36
services/web/app/views/layout-marketing.pug
Normal file
36
services/web/app/views/layout-marketing.pug
Normal file
@@ -0,0 +1,36 @@
|
||||
extends ./layout-base
|
||||
|
||||
include ./_mixins/formMessages
|
||||
include ./_mixins/bootstrap_js
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'marketing'
|
||||
|
||||
block body
|
||||
if (typeof suppressNavbar === "undefined")
|
||||
if bootstrapVersion === 5
|
||||
include layout/navbar-marketing-bootstrap-5
|
||||
else
|
||||
include layout/navbar-marketing
|
||||
|
||||
block content
|
||||
|
||||
if (typeof suppressFooter === "undefined")
|
||||
if showThinFooter
|
||||
if bootstrapVersion === 5
|
||||
include layout/thin-footer-bootstrap-5
|
||||
else
|
||||
include layout/thin-footer
|
||||
else
|
||||
include layout/fat-footer
|
||||
|
||||
if (typeof(suppressCookieBanner) == 'undefined')
|
||||
include _cookie_banner
|
||||
|
||||
if bootstrapVersion === 5
|
||||
!= moduleIncludes("contactModal-marketing-bootstrap-5", locals)
|
||||
else
|
||||
!= moduleIncludes("contactModal-marketing", locals)
|
||||
|
||||
block prepend foot-scripts
|
||||
+bootstrap-js(bootstrapVersion)
|
83
services/web/app/views/layout-react.pug
Normal file
83
services/web/app/views/layout-react.pug
Normal file
@@ -0,0 +1,83 @@
|
||||
//- This is used for pages that are migrated to Bootstrap 5 but don't use Bootstrap's own JS, instead using
|
||||
//- react-bootstrap for all Bootstrap components
|
||||
extends ./layout-base
|
||||
|
||||
include ./_mixins/formMessages
|
||||
include ./_mixins/bootstrap_js
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'marketing'
|
||||
|
||||
block isApplicationPageVar
|
||||
- isApplicationPage = true
|
||||
|
||||
block append meta
|
||||
if bootstrapVersion === 5
|
||||
- const canDisplayAdminMenu = hasAdminAccess()
|
||||
- const canDisplayAdminRedirect = canRedirectToAdminDomain()
|
||||
- const sessionUser = getSessionUser()
|
||||
- const staffAccess = sessionUser?.staffAccess
|
||||
- const canDisplaySplitTestMenu = hasFeature('saas') && (canDisplayAdminMenu || staffAccess?.splitTestMetrics || staffAccess?.splitTestManagement)
|
||||
- const canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
- const canDisplayScriptLogMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
- 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
|
||||
})
|
||||
|
||||
block body
|
||||
if (typeof suppressNavbar === "undefined")
|
||||
if bootstrapVersion === 5
|
||||
include layout/navbar-marketing-react-bootstrap-5
|
||||
else
|
||||
include layout/navbar-marketing
|
||||
|
||||
block content
|
||||
|
||||
if (typeof suppressFooter === "undefined")
|
||||
if showThinFooter
|
||||
if bootstrapVersion === 5
|
||||
include layout/thin-footer-bootstrap-5
|
||||
else
|
||||
include layout/thin-footer
|
||||
else
|
||||
if bootstrapVersion === 5
|
||||
include layout/fat-footer-react-bootstrap-5
|
||||
else
|
||||
include layout/fat-footer
|
||||
|
||||
if (typeof suppressCookieBanner === "undefined")
|
||||
include _cookie_banner
|
||||
|
||||
if bootstrapVersion === 3
|
||||
!= moduleIncludes("contactModal-marketing", locals)
|
||||
|
||||
block prepend foot-scripts
|
||||
//- Only include Bootstrap JS if using Bootstrap 3
|
||||
if bootstrapVersion === 3
|
||||
+bootstrap-js(3)
|
@@ -0,0 +1,28 @@
|
||||
extends ./layout-base
|
||||
|
||||
include ./_mixins/formMessages
|
||||
include ./_mixins/bootstrap_js
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'marketing'
|
||||
- isWebsiteRedesign = true
|
||||
|
||||
block body
|
||||
if (typeof(suppressNavbar) == "undefined")
|
||||
include layout/navbar-marketing-bootstrap-5
|
||||
|
||||
block content
|
||||
|
||||
if (typeof(suppressFooter) == "undefined")
|
||||
if showThinFooter
|
||||
include layout/thin-footer-bootstrap-5
|
||||
else
|
||||
include layout/fat-footer-website-redesign
|
||||
|
||||
if (typeof(suppressCookieBanner) == 'undefined')
|
||||
include _cookie_banner
|
||||
|
||||
!= moduleIncludes("contactModal-marketing-bootstrap-5", locals)
|
||||
|
||||
block prepend foot-scripts
|
||||
+bootstrap-js(5)
|
27
services/web/app/views/layout-website-redesign.pug
Normal file
27
services/web/app/views/layout-website-redesign.pug
Normal file
@@ -0,0 +1,27 @@
|
||||
extends ./layout-base
|
||||
|
||||
include ./_mixins/formMessages
|
||||
include ./_mixins/bootstrap_js
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'marketing'
|
||||
|
||||
block body
|
||||
if (typeof(suppressNavbar) == "undefined")
|
||||
include layout/navbar-website-redesign
|
||||
|
||||
block content
|
||||
|
||||
if (typeof(suppressFooter) == "undefined")
|
||||
if showThinFooter
|
||||
include layout/thin-footer
|
||||
else
|
||||
include layout/fat-footer-website-redesign
|
||||
|
||||
if (typeof(suppressCookieBanner) == 'undefined')
|
||||
include _cookie_banner
|
||||
|
||||
!= moduleIncludes("contactModal-marketing", locals)
|
||||
|
||||
block prepend foot-scripts
|
||||
+bootstrap-js(bootstrapVersion)
|
32
services/web/app/views/layout/fat-footer-base.pug
Normal file
32
services/web/app/views/layout/fat-footer-base.pug
Normal file
@@ -0,0 +1,32 @@
|
||||
.fat-footer-base
|
||||
.fat-footer-base-section.fat-footer-base-meta
|
||||
.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')}
|
||||
ul.fat-footer-base-item.list-unstyled.fat-footer-base-language
|
||||
if bootstrapVersion === 5
|
||||
include language-picker-bootstrap-5
|
||||
else
|
||||
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")
|
||||
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")
|
||||
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)")
|
||||
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")
|
||||
span.visually-hidden #{translate("app_on_x", {social: "LinkedIn"})}
|
@@ -0,0 +1 @@
|
||||
#footer-container
|
@@ -0,0 +1,84 @@
|
||||
footer.fat-footer.hidden-print.website-redesign-fat-footer
|
||||
.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-section
|
||||
h2.footer-section-heading #{translate('About')}
|
||||
|
||||
ul.list-unstyled
|
||||
li
|
||||
a(href="/about") #{translate('footer_about_us')}
|
||||
li
|
||||
a(href="/about/values") #{translate('our_values')}
|
||||
li
|
||||
a(href="/about/careers") #{translate('careers')}
|
||||
li
|
||||
a(href="/for/press") !{translate('press_and_awards')}
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="/latex/templates") #{translate('templates')}
|
||||
li
|
||||
a(href="/events/webinars") #{translate('webinars')}
|
||||
li
|
||||
a(href="/learn/latex/Tutorials") #{translate('tutorials')}
|
||||
li
|
||||
a(href="/learn/latex/Inserting_Images") #{translate('how_to_insert_images')}
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="/user/subscription/plans?itm_referrer=footer-for-indv-groups") !{translate('for_individuals_and_groups')}
|
||||
li
|
||||
a(href="/for/enterprises") #{translate('for_business')}
|
||||
li
|
||||
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"
|
||||
) #{translate('for_students')}
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="https://forms.gle/67PSpN1bLnjGCmPQ9") #{translate('let_us_know_what_you_think')}
|
||||
if user
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="/learn") #{translate('Documentation')}
|
||||
li
|
||||
a(href="/contact") #{translate('footer_contact_us')}
|
||||
li
|
||||
a(href="https://status.overleaf.com/") #{translate('website_status')}
|
||||
|
||||
include fat-footer-base
|
84
services/web/app/views/layout/fat-footer.pug
Normal file
84
services/web/app/views/layout/fat-footer.pug
Normal file
@@ -0,0 +1,84 @@
|
||||
footer.fat-footer.hidden-print
|
||||
.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-section
|
||||
h2.footer-section-heading #{translate('About')}
|
||||
|
||||
ul.list-unstyled
|
||||
li
|
||||
a(href="/about") #{translate('footer_about_us')}
|
||||
li
|
||||
a(href="/about/values") #{translate('our_values')}
|
||||
li
|
||||
a(href="/about/careers") #{translate('careers')}
|
||||
li
|
||||
a(href="/for/press") !{translate('press_and_awards')}
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="/latex/templates") #{translate('templates')}
|
||||
li
|
||||
a(href="/events/webinars") #{translate('webinars')}
|
||||
li
|
||||
a(href="/learn/latex/Tutorials") #{translate('tutorials')}
|
||||
li
|
||||
a(href="/learn/latex/Inserting_Images") #{translate('how_to_insert_images')}
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="/user/subscription/plans?itm_referrer=footer-for-indv-groups") !{translate('for_individuals_and_groups')}
|
||||
li
|
||||
a(href="/for/enterprises") #{translate('for_enterprise')}
|
||||
li
|
||||
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"
|
||||
) #{translate('for_students')}
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="https://forms.gle/67PSpN1bLnjGCmPQ9") #{translate('let_us_know_what_you_think')}
|
||||
if user
|
||||
li
|
||||
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')}
|
||||
li
|
||||
a(href="/learn") #{translate('Documentation')}
|
||||
li
|
||||
a(href="/contact") #{translate('footer_contact_us')}
|
||||
li
|
||||
a(href="https://status.overleaf.com/") #{translate('website_status')}
|
||||
|
||||
include fat-footer-base
|
@@ -0,0 +1,25 @@
|
||||
li.dropdown.dropup.subdued(dropdown).language-picker
|
||||
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'),
|
||||
tooltip=translate('language')
|
||||
title=translate('language')
|
||||
)
|
||||
span.material-symbols(aria-hidden="true") translate
|
||||
|
|
||||
span.language-picker-text #{settings.translatedLanguages[currentLngCode]}
|
||||
|
||||
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')
|
||||
| #{settings.translatedLanguages[subdomainDetails.lngCode]}
|
||||
if subdomainDetails.lngCode === currentLngCode
|
||||
span.material-symbols.dropdown-item-trailing-icon(aria-hidden="true") check
|
24
services/web/app/views/layout/language-picker.pug
Normal file
24
services/web/app/views/layout/language-picker.pug
Normal file
@@ -0,0 +1,24 @@
|
||||
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'),
|
||||
tooltip=translate('language')
|
||||
title=translate('language')
|
||||
)
|
||||
i.fa.fa-fw.fa-language
|
||||
|
|
||||
| #{settings.translatedLanguages[currentLngCode]}
|
||||
|
||||
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")
|
||||
| #{settings.translatedLanguages[subdomainDetails.lngCode]}
|
18
services/web/app/views/layout/layout-no-js.pug
Normal file
18
services/web/app/views/layout/layout-no-js.pug
Normal file
@@ -0,0 +1,18 @@
|
||||
doctype html
|
||||
html(lang="en")
|
||||
|
||||
- metadata = metadata || {}
|
||||
block vars
|
||||
|
||||
head
|
||||
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")
|
||||
|
||||
link(rel="icon", href="/favicon.ico")
|
||||
|
||||
if buildCssPath
|
||||
link(rel="stylesheet", href=buildCssPath())
|
||||
|
||||
block body
|
201
services/web/app/views/layout/navbar-marketing-bootstrap-5.pug
Normal file
201
services/web/app/views/layout/navbar-marketing-bootstrap-5.pug
Normal file
@@ -0,0 +1,201 @@
|
||||
include ../_mixins/navbar
|
||||
|
||||
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}
|
||||
else
|
||||
a(href='/', aria-label=settings.appName).navbar-brand
|
||||
|
||||
- var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on')
|
||||
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"}'
|
||||
) #{translate("upgrade")}
|
||||
|
||||
- var canDisplayAdminMenu = hasAdminAccess()
|
||||
- var canDisplayAdminRedirect = canRedirectToAdminDomain()
|
||||
- var canDisplaySplitTestMenu = hasFeature('saas') && (canDisplayAdminMenu || (getSessionUser() && getSessionUser().staffAccess && (getSessionUser().staffAccess.splitTestMetrics || getSessionUser().staffAccess.splitTestManagement)))
|
||||
- var canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
- var canDisplayScriptLogMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
|
||||
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')
|
||||
)
|
||||
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)
|
||||
+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"}
|
||||
)
|
||||
| Admin
|
||||
span.caret
|
||||
+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
|
||||
if canDisplayAdminRedirect
|
||||
+dropdown-menu-link-item()(href=settings.adminUrl) Switch to Admin
|
||||
if canDisplaySplitTestMenu
|
||||
+dropdown-menu-link-item()(href="/admin/split-test") Manage Feature Flags
|
||||
if canDisplaySurveyMenu
|
||||
+dropdown-menu-link-item()(href="/admin/survey") Manage Surveys
|
||||
if canDisplayScriptLogMenu
|
||||
+dropdown-menu-link-item()(href="/admin/script-logs") View Script Logs
|
||||
|
||||
// loop over header_extras
|
||||
each item in nav.header_extras
|
||||
-
|
||||
if ((item.only_when_logged_in && getSessionUser())
|
||||
|| (item.only_when_logged_out && (!getSessionUser()))
|
||||
|| (!item.only_when_logged_out && !item.only_when_logged_in && !item.only_content_pages)
|
||||
|| (item.only_content_pages && (typeof suppressNavContentLinks === "undefined" || !suppressNavContentLinks))
|
||||
){
|
||||
var showNavItem = true
|
||||
} else {
|
||||
var showNavItem = false
|
||||
}
|
||||
|
||||
if showNavItem
|
||||
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"}
|
||||
)
|
||||
| !{translate(item.text)}
|
||||
span.caret
|
||||
+dropdown-menu.dropdown-menu-end
|
||||
each child in item.dropdown
|
||||
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"})
|
||||
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' }
|
||||
) !{translate(child.text)}
|
||||
else
|
||||
+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' }
|
||||
) !{translate(item.text)}
|
||||
else
|
||||
| !{translate(item.text)}
|
||||
|
||||
// logged out
|
||||
if !getSessionUser()
|
||||
// register link
|
||||
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' }
|
||||
) #{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' }
|
||||
) #{translate('log_in')}
|
||||
|
||||
// projects link and account menu
|
||||
if getSessionUser()
|
||||
+nav-item
|
||||
+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"}
|
||||
)
|
||||
| #{translate('Account')}
|
||||
span.caret
|
||||
+dropdown-menu.dropdown-menu-end
|
||||
+dropdown-menu-item
|
||||
div.disabled.dropdown-item #{getSessionUser().email}
|
||||
+dropdown-menu-divider
|
||||
+dropdown-menu-link-item()(href="/user/settings") #{translate('Account Settings')}
|
||||
if nav.showSubscriptionLink
|
||||
+dropdown-menu-link-item()(href="/user/subscription") #{translate('subscription')}
|
||||
+dropdown-menu-divider
|
||||
+dropdown-menu-item
|
||||
//-
|
||||
The button is outside the form but still belongs to it via the form attribute. The reason to do
|
||||
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"
|
||||
)
|
||||
| #{translate('log_out')}
|
||||
form(
|
||||
method="POST",
|
||||
action="/logout",
|
||||
id="logOutForm"
|
||||
)
|
||||
input(name='_csrf', type='hidden', value=csrfToken)
|
@@ -0,0 +1 @@
|
||||
#navbar-container
|
197
services/web/app/views/layout/navbar-marketing.pug
Normal file
197
services/web/app/views/layout/navbar-marketing.pug
Normal file
@@ -0,0 +1,197 @@
|
||||
nav.navbar.navbar-default.navbar-main(class={
|
||||
'website-redesign-navbar': isWebsiteRedesign
|
||||
})
|
||||
.container-fluid
|
||||
.navbar-header
|
||||
if (typeof(suppressNavbarRight) == "undefined")
|
||||
button.navbar-toggle.collapsed(
|
||||
type="button",
|
||||
data-toggle="collapse",
|
||||
data-target="#navbar-main-collapse"
|
||||
aria-label="Toggle " + translate('navigation')
|
||||
)
|
||||
i.fa.fa-bars(aria-hidden="true")
|
||||
- var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on')
|
||||
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"}'
|
||||
) #{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}
|
||||
else
|
||||
a(href='/', aria-label=settings.appName).navbar-brand
|
||||
|
||||
- var canDisplayAdminMenu = hasAdminAccess()
|
||||
- var canDisplayAdminRedirect = canRedirectToAdminDomain()
|
||||
- var canDisplaySplitTestMenu = hasFeature('saas') && (canDisplayAdminMenu || (getSessionUser() && getSessionUser().staffAccess && (getSessionUser().staffAccess.splitTestMetrics || getSessionUser().staffAccess.splitTestManagement)))
|
||||
- var canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
- var canDisplayScriptLogMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
|
||||
if (typeof(suppressNavbarRight) == "undefined")
|
||||
.navbar-collapse.collapse#navbar-main-collapse
|
||||
ul.nav.navbar-nav.navbar-right
|
||||
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"}
|
||||
)
|
||||
| Admin
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
if canDisplayAdminMenu
|
||||
li
|
||||
a(href="/admin") Manage Site
|
||||
li
|
||||
a(href="/admin/user") Manage Users
|
||||
li
|
||||
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
|
||||
if canDisplaySurveyMenu
|
||||
li
|
||||
a(href="/admin/survey") Manage Surveys
|
||||
if canDisplayScriptLogMenu
|
||||
li
|
||||
a(href="/admin/script-logs") View Script Logs
|
||||
|
||||
// loop over header_extras
|
||||
each item in nav.header_extras
|
||||
-
|
||||
if ((item.only_when_logged_in && getSessionUser())
|
||||
|| (item.only_when_logged_out && (!getSessionUser()))
|
||||
|| (!item.only_when_logged_out && !item.only_when_logged_in && !item.only_content_pages)
|
||||
|| (item.only_content_pages && (typeof(suppressNavContentLinks) == "undefined" || !suppressNavContentLinks))
|
||||
){
|
||||
var showNavItem = true
|
||||
} else {
|
||||
var showNavItem = false
|
||||
}
|
||||
|
||||
if showNavItem
|
||||
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"}
|
||||
)
|
||||
| !{translate(item.text)}
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
each child in item.dropdown
|
||||
if child.divider
|
||||
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"})
|
||||
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"
|
||||
event-segmentation={item: item.trackingKey, location: 'top-menu'}
|
||||
) !{translate(child.text)}
|
||||
else
|
||||
| !{translate(child.text)}
|
||||
else
|
||||
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' }
|
||||
) !{translate(item.text)}
|
||||
else
|
||||
| !{translate(item.text)}
|
||||
|
||||
// logged out
|
||||
if !getSessionUser()
|
||||
// register link
|
||||
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' }
|
||||
) #{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' }
|
||||
) #{translate('log_in')}
|
||||
|
||||
// projects link and account menu
|
||||
if getSessionUser()
|
||||
li
|
||||
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"}
|
||||
)
|
||||
| #{translate('Account')}
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
li
|
||||
div.subdued #{getSessionUser().email}
|
||||
li.divider.hidden-xs.hidden-sm
|
||||
li
|
||||
a(href="/user/settings") #{translate('Account Settings')}
|
||||
if nav.showSubscriptionLink
|
||||
li
|
||||
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)
|
||||
button.btn-link.text-left.dropdown-menu-button #{translate('log_out')}
|
195
services/web/app/views/layout/navbar-website-redesign.pug
Normal file
195
services/web/app/views/layout/navbar-website-redesign.pug
Normal file
@@ -0,0 +1,195 @@
|
||||
nav.navbar.navbar-default.navbar-main.website-redesign-navbar
|
||||
.container-fluid
|
||||
.navbar-header
|
||||
if (typeof(suppressNavbarRight) == "undefined")
|
||||
button.navbar-toggle.collapsed(
|
||||
type="button",
|
||||
data-toggle="collapse",
|
||||
data-target="#navbar-main-collapse"
|
||||
aria-label="Toggle " + translate('navigation')
|
||||
)
|
||||
i.fa.fa-bars(aria-hidden="true")
|
||||
- var enableUpgradeButton = projectDashboardReact && usersBestSubscription && (usersBestSubscription.type === 'free' || usersBestSubscription.type === 'standalone-ai-add-on')
|
||||
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"}'
|
||||
) #{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}
|
||||
else
|
||||
a(href='/', aria-label=settings.appName).navbar-brand
|
||||
|
||||
- var canDisplayAdminMenu = hasAdminAccess()
|
||||
- var canDisplayAdminRedirect = canRedirectToAdminDomain()
|
||||
- var canDisplaySplitTestMenu = hasFeature('saas') && (canDisplayAdminMenu || (getSessionUser() && getSessionUser().staffAccess && (getSessionUser().staffAccess.splitTestMetrics || getSessionUser().staffAccess.splitTestManagement)))
|
||||
- var canDisplaySurveyMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
- var canDisplayScriptLogMenu = hasFeature('saas') && canDisplayAdminMenu
|
||||
|
||||
if (typeof(suppressNavbarRight) == "undefined")
|
||||
.navbar-collapse.collapse#navbar-main-collapse
|
||||
ul.nav.navbar-nav.navbar-right
|
||||
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"}
|
||||
)
|
||||
| Admin
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
if canDisplayAdminMenu
|
||||
li
|
||||
a(href="/admin") Manage Site
|
||||
li
|
||||
a(href="/admin/user") Manage Users
|
||||
li
|
||||
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
|
||||
if canDisplaySurveyMenu
|
||||
li
|
||||
a(href="/admin/survey") Manage Surveys
|
||||
if canDisplayScriptLogMenu
|
||||
li
|
||||
a(href="/admin/script-logs") View Script Logs
|
||||
|
||||
// loop over header_extras
|
||||
each item in nav.header_extras
|
||||
-
|
||||
if ((item.only_when_logged_in && getSessionUser())
|
||||
|| (item.only_when_logged_out && (!getSessionUser()))
|
||||
|| (!item.only_when_logged_out && !item.only_when_logged_in && !item.only_content_pages)
|
||||
|| (item.only_content_pages && (typeof(suppressNavContentLinks) == "undefined" || !suppressNavContentLinks))
|
||||
){
|
||||
var showNavItem = true
|
||||
} else {
|
||||
var showNavItem = false
|
||||
}
|
||||
|
||||
if showNavItem
|
||||
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"}
|
||||
)
|
||||
| !{translate(item.text)}
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
each child in item.dropdown
|
||||
if child.divider
|
||||
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"})
|
||||
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"
|
||||
event-segmentation={item: child.trackingKey, location: 'top-menu'}
|
||||
) !{translate(child.text)}
|
||||
else
|
||||
| !{translate(child.text)}
|
||||
else
|
||||
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' }
|
||||
) !{translate(item.text)}
|
||||
else
|
||||
| !{translate(item.text)}
|
||||
|
||||
// logged out
|
||||
if !getSessionUser()
|
||||
// register link
|
||||
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' }
|
||||
) #{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' }
|
||||
) #{translate('log_in')}
|
||||
|
||||
// projects link and account menu
|
||||
if getSessionUser()
|
||||
li.secondary
|
||||
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"}
|
||||
)
|
||||
| #{translate('Account')}
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
li
|
||||
div.subdued #{getSessionUser().email}
|
||||
li.divider.hidden-xs.hidden-sm
|
||||
li
|
||||
a(href="/user/settings") #{translate('Account Settings')}
|
||||
if nav.showSubscriptionLink
|
||||
li
|
||||
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)
|
||||
button.btn-link.text-left.dropdown-menu-button #{translate('log_out')}
|
38
services/web/app/views/layout/thin-footer-bootstrap-5.pug
Normal file
38
services/web/app/views/layout/thin-footer-bootstrap-5.pug
Normal file
@@ -0,0 +1,38 @@
|
||||
footer.site-footer
|
||||
- var showLanguagePicker = Object.keys(settings.i18n.subdomainLang).length > 1
|
||||
- var hasCustomLeftNav = nav.left_footer && nav.left_footer.length > 0
|
||||
.site-footer-content.hidden-print
|
||||
.row
|
||||
ul.site-footer-items.col-lg-9
|
||||
if !settings.nav.hide_powered_by
|
||||
li
|
||||
//- year of Server Pro release, static
|
||||
| © 2025
|
||||
|
|
||||
a(href='https://www.overleaf.com/for/enterprises') Powered by Overleaf
|
||||
|
||||
if showLanguagePicker || hasCustomLeftNav
|
||||
li
|
||||
strong.text-muted |
|
||||
|
||||
if showLanguagePicker
|
||||
include language-picker-bootstrap-5
|
||||
|
||||
if showLanguagePicker && hasCustomLeftNav
|
||||
li
|
||||
strong.text-muted |
|
||||
|
||||
each item in nav.left_footer
|
||||
li
|
||||
if item.url
|
||||
a(href=item.url, class=item.class) !{translate(item.text)}
|
||||
else
|
||||
| !{item.text}
|
||||
|
||||
ul.site-footer-items.col-lg-3.text-end
|
||||
each item in nav.right_footer
|
||||
li
|
||||
if item.url
|
||||
a(href=item.url, class=item.class, aria-label=item.label) !{item.text}
|
||||
else
|
||||
| !{item.text}
|
40
services/web/app/views/layout/thin-footer.pug
Normal file
40
services/web/app/views/layout/thin-footer.pug
Normal file
@@ -0,0 +1,40 @@
|
||||
footer.site-footer
|
||||
- var showLanguagePicker = Object.keys(settings.i18n.subdomainLang).length > 1
|
||||
- var hasCustomLeftNav = nav.left_footer && nav.left_footer.length > 0
|
||||
.site-footer-content.hidden-print
|
||||
.row
|
||||
ul.col-md-9
|
||||
if hasFeature('saas')
|
||||
li © #{new Date().getFullYear()} Overleaf
|
||||
else if !settings.nav.hide_powered_by
|
||||
li
|
||||
//- year of Server Pro release, static
|
||||
| © 2025
|
||||
|
|
||||
a(href='https://www.overleaf.com/for/enterprises') Powered by Overleaf
|
||||
|
||||
if showLanguagePicker || hasCustomLeftNav
|
||||
li
|
||||
strong.text-muted |
|
||||
|
||||
if showLanguagePicker
|
||||
include language-picker
|
||||
|
||||
if showLanguagePicker && hasCustomLeftNav
|
||||
li
|
||||
strong.text-muted |
|
||||
|
||||
each item in nav.left_footer
|
||||
li
|
||||
if item.url
|
||||
a(href=item.url, class=item.class) !{translate(item.text)}
|
||||
else
|
||||
| !{item.text}
|
||||
|
||||
ul.col-md-3.text-right
|
||||
each item in nav.right_footer
|
||||
li
|
||||
if item.url
|
||||
a(href=item.url, class=item.class, aria-label=item.label) !{item.text}
|
||||
else
|
||||
| !{item.text}
|
61
services/web/app/views/project/editor/_meta.pug
Normal file
61
services/web/app/views/project/editor/_meta.pug
Normal file
@@ -0,0 +1,61 @@
|
||||
meta(name="ol-project_id" content=project_id)
|
||||
meta(name="ol-projectName" content=projectName)
|
||||
meta(name="ol-userSettings" data-type="json" content=userSettings)
|
||||
meta(name="ol-user" data-type="json" content=user)
|
||||
meta(name="ol-labsExperiments" data-type="json" content=labsExperiments)
|
||||
meta(name="ol-learnedWords" data-type="json" content=learnedWords)
|
||||
meta(name="ol-anonymous" data-type="boolean" content=anonymous)
|
||||
meta(name="ol-brandVariation" data-type="json" content=brandVariation)
|
||||
meta(name="ol-isTokenMember" data-type="boolean" content=isTokenMember)
|
||||
meta(name="ol-isRestrictedTokenMember" data-type="boolean" content=isRestrictedTokenMember)
|
||||
meta(name="ol-maxDocLength" data-type="json" content=maxDocLength)
|
||||
meta(name="ol-maxReconnectGracefullyIntervalMs" data-type="json" content=maxReconnectGracefullyIntervalMs)
|
||||
meta(name="ol-wikiEnabled" data-type="boolean" content=settings.proxyLearn)
|
||||
meta(name="ol-chatEnabled" data-type="boolean" content=chatEnabled)
|
||||
meta(name="ol-projectHistoryBlobsEnabled" data-type="boolean" content=projectHistoryBlobsEnabled)
|
||||
meta(name="ol-gitBridgePublicBaseUrl" content=gitBridgePublicBaseUrl)
|
||||
meta(name="ol-gitBridgeEnabled" data-type="boolean" content=gitBridgeEnabled)
|
||||
meta(name="ol-compilesUserContentDomain" content=settings.compilesUserContentDomain)
|
||||
//- enable doc hash checking for all projects
|
||||
//- used in public/js/libs/sharejs.js
|
||||
meta(name="ol-useShareJsHash" data-type="boolean" content=true)
|
||||
meta(name="ol-wsUrl" data-type="string" content=wsUrl)
|
||||
meta(name="ol-wsRetryHandshake" data-type="json" content=settings.wsRetryHandshake)
|
||||
meta(name="ol-debugPdfDetach" data-type="boolean" content=debugPdfDetach)
|
||||
meta(name="ol-showSymbolPalette" data-type="boolean" content=showSymbolPalette)
|
||||
meta(name="ol-symbolPaletteAvailable" data-type="boolean" content=symbolPaletteAvailable)
|
||||
meta(name="ol-showAiErrorAssistant" data-type="boolean" content=showAiErrorAssistant)
|
||||
meta(name="ol-detachRole" data-type="string" content=detachRole)
|
||||
meta(name="ol-allowedImageNames" data-type="json" content=allowedImageNames)
|
||||
meta(name="ol-languages" data-type="json" content=languages)
|
||||
meta(name="ol-editorThemes" data-type="json" content=editorThemes)
|
||||
meta(name="ol-legacyEditorThemes" data-type="json" content=legacyEditorThemes)
|
||||
meta(name="ol-showUpgradePrompt" data-type="boolean" content=showUpgradePrompt)
|
||||
meta(name="ol-showSupport", data-type="boolean" content=showSupport)
|
||||
meta(name="ol-showTemplatesServerPro", data-type="boolean" content=showTemplatesServerPro)
|
||||
meta(name="ol-hasTrackChangesFeature", data-type="boolean" content=hasTrackChangesFeature)
|
||||
meta(name="ol-inactiveTutorials", data-type="json" content=user.inactiveTutorials)
|
||||
meta(name="ol-projectTags" data-type="json" content=projectTags)
|
||||
meta(name="ol-ro-mirror-on-client-no-local-storage" data-type="boolean" content=roMirrorOnClientNoLocalStorage)
|
||||
meta(name="ol-isSaas" data-type="boolean" content=isSaas)
|
||||
meta(name="ol-shouldLoadHotjar" data-type="boolean" content=shouldLoadHotjar)
|
||||
meta(name="ol-isReviewerRoleEnabled" data-type="boolean" content=isReviewerRoleEnabled)
|
||||
meta(name="ol-odcRole" data-type="string" content=odcRole)
|
||||
meta(name="ol-isPaywallChangeCompileTimeoutEnabled" data-type="boolean" content=isPaywallChangeCompileTimeoutEnabled)
|
||||
meta(name='ol-customerIoEnabled' data-type="boolean" content=customerIoEnabled)
|
||||
if(isPaywallChangeCompileTimeoutEnabled)
|
||||
//- expose plans info to show prices in paywall-change-compile-timeout test
|
||||
meta(name="ol-paywallPlans", data-type="json" content=paywallPlans)
|
||||
if(isOverleafAssistBundleEnabled)
|
||||
//- expose plans info to show prices in paywall-change-compile-timeout test
|
||||
meta(name="ol-addonPrices", data-type="json" content=addonPrices)
|
||||
// translations for the loading page, before i18n has loaded in the client
|
||||
meta(name="ol-loadingText", data-type="string" content=translate("loading"))
|
||||
meta(name="ol-translationIoNotLoaded", data-type="string" content=translate("could_not_connect_to_websocket_server"))
|
||||
meta(name="ol-translationLoadErrorMessage", data-type="string" content=translate("could_not_load_translations"))
|
||||
meta(name="ol-translationUnableToJoin", data-type="string" content=translate("could_not_connect_to_collaboration_server"))
|
||||
|
||||
if (settings.overleaf != null)
|
||||
meta(name="ol-overallThemes" data-type="json" content=overallThemes)
|
||||
|
||||
!= moduleIncludes("editor:meta", locals)
|
37
services/web/app/views/project/editor/new_from_template.pug
Normal file
37
services/web/app/views/project/editor/new_from_template.pug
Normal file
@@ -0,0 +1,37 @@
|
||||
extends ../../layout-marketing
|
||||
|
||||
block vars
|
||||
- var suppressFooter = true
|
||||
- var suppressCookieBanner = true
|
||||
- var suppressSkipToContent = true
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
.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 .
|
||||
|
||||
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")
|
17
services/web/app/views/project/editor/socket_diagnostics.pug
Normal file
17
services/web/app/views/project/editor/socket_diagnostics.pug
Normal file
@@ -0,0 +1,17 @@
|
||||
extends ../../layout-marketing
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressGoogleAnalytics = true
|
||||
- isWebsiteRedesign = 'true'
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/socket-diagnostics'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
#socket-diagnostics
|
||||
|
||||
block prepend foot-scripts
|
||||
script(type="text/javascript", nonce=scriptNonce, src=(wsUrl || '/socket.io') + '/socket.io.js', defer=deferScripts)
|
17
services/web/app/views/project/ide-react-detached.pug
Normal file
17
services/web/app/views/project/ide-react-detached.pug
Normal file
@@ -0,0 +1,17 @@
|
||||
extends ../layout-react
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'ide-detached'
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressSkipToContent = true
|
||||
- var suppressCookieBanner = true
|
||||
- metadata.robotsNoindexNofollow = true
|
||||
|
||||
block content
|
||||
#pdf-preview-detached-root()
|
||||
|
||||
block append meta
|
||||
include editor/_meta
|
28
services/web/app/views/project/ide-react.pug
Normal file
28
services/web/app/views/project/ide-react.pug
Normal file
@@ -0,0 +1,28 @@
|
||||
extends ../layout-react
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressSkipToContent = true
|
||||
- var deferScripts = true
|
||||
- metadata.robotsNoindexNofollow = true
|
||||
- enableIeeeBranding = false
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/ide'
|
||||
|
||||
block content
|
||||
main#ide-root
|
||||
.loading-screen
|
||||
.loading-screen-brand-container
|
||||
.loading-screen-brand(style="height: 20%;")
|
||||
h3.loading-screen-label #{translate("loading")}
|
||||
span.loading-screen-ellip .
|
||||
span.loading-screen-ellip .
|
||||
span.loading-screen-ellip .
|
||||
|
||||
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)
|
21
services/web/app/views/project/invite/not-valid.pug
Normal file
21
services/web/app/views/project/invite/not-valid.pug
Normal file
@@ -0,0 +1,21 @@
|
||||
extends ../../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-8.col-md-offset-2
|
||||
.card.project-invite-invalid
|
||||
.page-header.text-centered
|
||||
h1 #{translate("invite_not_valid")}
|
||||
.row.text-center
|
||||
.col-md-12
|
||||
p
|
||||
| #{translate("invite_not_valid_description")}.
|
||||
.row.text-center.actions
|
||||
.col-md-12
|
||||
a.btn.btn-secondary-info.btn-secondary(href="/project") #{translate("back_to_your_projects")}
|
||||
|
37
services/web/app/views/project/invite/show.pug
Normal file
37
services/web/app/views/project/invite/show.pug
Normal file
@@ -0,0 +1,37 @@
|
||||
extends ../../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-8.col-md-offset-2
|
||||
.card.project-invite-accept
|
||||
.page-header.text-centered
|
||||
h1 #{translate("user_wants_you_to_see_project", {username:owner.first_name, projectname:""})}
|
||||
br
|
||||
em #{project.name}
|
||||
.row.text-center
|
||||
.col-md-12
|
||||
p
|
||||
| #{translate("accepting_invite_as")}
|
||||
em #{user.email}
|
||||
.row
|
||||
.col-md-12
|
||||
form.form(
|
||||
data-ol-regular-form
|
||||
method="POST",
|
||||
action="/project/"+invite.projectId+"/invite/token/"+token+"/accept"
|
||||
)
|
||||
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"
|
||||
data-ol-disabled-inflight
|
||||
)
|
||||
span(data-ol-inflight="idle") #{translate("join_project")}
|
||||
span(hidden data-ol-inflight="pending") #{translate("joining")}…
|
||||
.form-group.text-center
|
43
services/web/app/views/project/list-react.pug
Normal file
43
services/web/app/views/project/list-react.pug
Normal file
@@ -0,0 +1,43 @@
|
||||
extends ../layout-react
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/project-list'
|
||||
|
||||
block vars
|
||||
- const suppressNavContentLinks = true
|
||||
- const suppressNavbar = true
|
||||
- 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-hasIndividualRecurlySubscription" data-type="boolean" content=hasIndividualRecurlySubscription)
|
||||
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
|
17
services/web/app/views/project/token/access-react.pug
Normal file
17
services/web/app/views/project/token/access-react.pug
Normal file
@@ -0,0 +1,17 @@
|
||||
extends ../../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/token-access'
|
||||
|
||||
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)
|
||||
|
||||
block content
|
||||
.content.content-alt#main-content
|
||||
div#token-access-page
|
16
services/web/app/views/project/token/sharing-updates.pug
Normal file
16
services/web/app/views/project/token/sharing-updates.pug
Normal file
@@ -0,0 +1,16 @@
|
||||
extends ../../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/sharing-updates'
|
||||
|
||||
block vars
|
||||
- var suppressFooter = true
|
||||
- var suppressCookieBanner = true
|
||||
- var suppressSkipToContent = true
|
||||
|
||||
block append meta
|
||||
meta(name="ol-project_id" data-type="string" content=projectId)
|
||||
|
||||
block content
|
||||
.content.content-alt#main-content
|
||||
div#sharing-updates-page
|
49
services/web/app/views/referal/bonus.pug
Normal file
49
services/web/app/views/referal/bonus.pug
Normal file
@@ -0,0 +1,49 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
.content.content-alt#main-content
|
||||
.container.bonus
|
||||
.row
|
||||
.col-md-8.col-md-offset-2
|
||||
.card
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-10.col-md-offset-1
|
||||
if (refered_user_count > 0)
|
||||
p.thanks The Overleaf Bonus Program has been discontinued, but you'll continue to have access to the features you already earned.
|
||||
else
|
||||
p.thanks The Overleaf Bonus Program has been discontinued.
|
||||
p.thanks Please <a href="/contact">contact us</a> if you have any questions.
|
||||
|
||||
if (refered_user_count > 0)
|
||||
.row.ab-bonus
|
||||
.col-md-10.col-md-offset-1.bonus-banner(style="position: relative; height: 30px; margin-top: 20px;")
|
||||
- for (var i = 0; i <= 10; i++) {
|
||||
if (refered_user_count == i)
|
||||
.number(style="left: "+i+"0%").active #{i}
|
||||
else
|
||||
.number(style="left: "+i+"0%") #{i}
|
||||
- }
|
||||
|
||||
.row.ab-bonus
|
||||
.col-md-10.col-md-offset-1.bonus-banner
|
||||
.progress
|
||||
.progress-bar.progress-bar-info(style="width: "+refered_user_count+"0%")
|
||||
|
||||
.row.ab-bonus
|
||||
.col-md-10.col-md-offset-1.bonus-banner(style="position: relative; height: 110px;")
|
||||
.perk(style="left: 10%;", class = refered_user_count >= 1 ? "active" : "") #{translate("one_free_collab")}
|
||||
.perk(style="left: 30%;", class = refered_user_count >= 3 ? "active" : "") #{translate("three_free_collab")}
|
||||
.perk(style="left: 60%;", class = refered_user_count >= 6 ? "active" : "") #{translate("free_dropbox_and_history")} + #{translate("three_free_collab")}
|
||||
.perk(style="left: 90%;", class = refered_user_count >= 9 ? "active" : "") #{translate("free_dropbox_and_history")} + #{translate("unlimited_collabs")}
|
||||
.row
|
||||
|
||||
.row.ab-bonus
|
||||
.col-md-10.col-md-offset-1.bonus-banner.bonus-status
|
||||
if (refered_user_count == 1)
|
||||
p.thanks You’ve introduced <strong>1</strong> person to #{settings.appName}.
|
||||
else
|
||||
p.thanks You’ve introduced <strong>#{refered_user_count}</strong> people to #{settings.appName}.
|
15
services/web/app/views/subscriptions/add-seats.pug
Normal file
15
services/web/app/views/subscriptions/add-seats.pug
Normal file
@@ -0,0 +1,15 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/add-seats'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-subscriptionData" data-type="json" content=subscriptionData)
|
||||
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)
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
#add-seats-root
|
@@ -0,0 +1,10 @@
|
||||
extends ../layout-react
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/canceled-subscription'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-user" data-type="json" content=user)
|
||||
|
||||
block content
|
||||
main.content.content-alt#subscription-canceled-root
|
34
services/web/app/views/subscriptions/dashboard-react.pug
Normal file
34
services/web/app/views/subscriptions/dashboard-react.pug
Normal file
@@ -0,0 +1,34 @@
|
||||
extends ../layout-react
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/dashboard'
|
||||
|
||||
block head-scripts
|
||||
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-user" data-type="json" content=user)
|
||||
if (personalSubscription && personalSubscription.payment)
|
||||
meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey)
|
||||
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
|
@@ -0,0 +1,10 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/manually-collected-subscription'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-groupName", data-type="string", content=groupName)
|
||||
|
||||
block content
|
||||
main.content.content-alt#manually-collected-subscription-root
|
@@ -0,0 +1,10 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/missing-billing-information'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-groupName", data-type="string", content=groupName)
|
||||
|
||||
block content
|
||||
main.content.content-alt#missing-billing-information-root
|
86
services/web/app/views/subscriptions/plans/_faq_new.pug
Normal file
86
services/web/app/views/subscriptions/plans/_faq_new.pug
Normal file
@@ -0,0 +1,86 @@
|
||||
include ./_plans_faq_tabs
|
||||
include ../../_mixins/eyebrow
|
||||
|
||||
- var managingYourSubscription = 'managingYourSubscription'
|
||||
- var overleafIndividualPlans = 'overleafIndividualPlans'
|
||||
- var overleafGroupPlans = 'overleafGroupPlans'
|
||||
.plans-faq
|
||||
.row.row-spaced-extra-large
|
||||
.col-md-12.faq-heading-container
|
||||
h2
|
||||
+eyebrow(translate("frequently_asked_questions"))
|
||||
| #{translate("your_questions_answered")}
|
||||
|
||||
.row
|
||||
.col-xs-12
|
||||
div(
|
||||
class={
|
||||
'plans-faq-tabs': bootstrapVersion === 5,
|
||||
'ol-tabs': bootstrapVersion === 5,
|
||||
'ol-tabs-scrollable': bootstrapVersion === 3
|
||||
}
|
||||
)
|
||||
.nav-tabs-container
|
||||
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
|
||||
}
|
||||
)
|
||||
a(
|
||||
role="tab"
|
||||
data-toggle="tab"
|
||||
data-bs-toggle="tab"
|
||||
href='#' + managingYourSubscription
|
||||
aria-controls=managingYourSubscription
|
||||
class={
|
||||
active: bootstrapVersion === 5
|
||||
}
|
||||
)
|
||||
| #{translate('managing_your_subscription')}
|
||||
li(role="presentation")
|
||||
a(
|
||||
role="tab"
|
||||
data-toggle="tab"
|
||||
data-bs-toggle="tab"
|
||||
href='#' + overleafIndividualPlans
|
||||
aria-controls=overleafIndividualPlans
|
||||
)
|
||||
| #{translate('overleaf_individual_plans')}
|
||||
li(role="presentation")
|
||||
a(
|
||||
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()
|
||||
|
||||
.row
|
||||
.col-xs-12.plans-faq-support
|
||||
span #{translate('still_have_questions')}
|
||||
button(data-ol-open-contact-form-modal="general")
|
||||
span(style="margin-right: 4px") #{translate('contact_support')}
|
||||
i.icon-md.material-symbols.material-symbols-rounded.material-symbols-arrow-right(aria-hidden="true") arrow_right_alt
|
356
services/web/app/views/subscriptions/plans/_plans_faq_tabs.pug
Normal file
356
services/web/app/views/subscriptions/plans/_plans_faq_tabs.pug
Normal file
@@ -0,0 +1,356 @@
|
||||
//- 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`)
|
||||
|
||||
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"
|
||||
)
|
||||
| Can I change plans or cancel later?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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 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"
|
||||
)
|
||||
| If I change or cancel my Overleaf plan, will I lose my projects?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="managingYourSubscriptionQ2")
|
||||
.custom-accordion-body
|
||||
| No. Changing or canceling your plan won’t 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"
|
||||
)
|
||||
| Can I pay by invoice or purchase order?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="managingYourSubscriptionQ3")
|
||||
.custom-accordion-body
|
||||
| This is possible when you’re 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"
|
||||
)
|
||||
| How do I view/update the credit card being charged for my subscription?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="managingYourSubscriptionQ4")
|
||||
.custom-accordion-body
|
||||
| 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' }
|
||||
)
|
||||
span Subscription
|
||||
| .
|
||||
|
||||
|
||||
|
||||
|
||||
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"
|
||||
)
|
||||
| How does the free trial work?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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 there’s 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' }
|
||||
)
|
||||
span Subscription
|
||||
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"
|
||||
)
|
||||
| What’s a collaborator on an Overleaf individual subscription?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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.
|
||||
|
||||
.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"
|
||||
)
|
||||
| The individual Standard plan has 10 project collaborators, does it mean that 10 people will be upgraded?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="overleafIndividualPlansQ3")
|
||||
.custom-accordion-body
|
||||
span No. Only the subscriber’s 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) they’re 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"
|
||||
)
|
||||
| Do collaborators also have access to the editing and collaboration features I’ve paid for?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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 for the project(s) they’re 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"
|
||||
)
|
||||
| Can I purchase an individual plan on behalf of someone else?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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, you’ll 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"
|
||||
)
|
||||
| Who is eligible for the Student plan?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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"
|
||||
)
|
||||
| Can I transfer an individual subscription to someone else?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="overleafIndividualPlansQ7")
|
||||
.custom-accordion-body
|
||||
| No. Individual plans can’t be transferred.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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"
|
||||
)
|
||||
| What’s the difference between users and collaborators on an Overleaf group subscription?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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 plan’s 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.
|
||||
.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"
|
||||
)
|
||||
| What is the benefit of purchasing an Overleaf Group plan?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="overleafGroupPlansQ2")
|
||||
.custom-accordion-body
|
||||
| Our Group subscriptions allow you to purchase access to our premium features for multiple people. They’re 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' }
|
||||
)
|
||||
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"
|
||||
)
|
||||
| Who is eligible for the educational discount?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") 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.
|
||||
.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"
|
||||
)
|
||||
| How do I add more licenses to my group subscription, and what will it cost?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="overleafGroupPlansQ4")
|
||||
.custom-accordion-body
|
||||
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' }
|
||||
)
|
||||
span subscription management page
|
||||
| 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' }
|
||||
)
|
||||
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
|
||||
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' }
|
||||
)
|
||||
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"
|
||||
)
|
||||
| How do I upgrade my plan from Group Standard to Group Professional?
|
||||
span.custom-accordion-icon
|
||||
i.material-symbols.material-symbols-outlined(aria-hidden="true") keyboard_arrow_down
|
||||
.collapse(id="overleafGroupPlansQ5")
|
||||
.custom-accordion-body
|
||||
| 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' }
|
||||
)
|
||||
span subscription management page
|
||||
| .
|
11
services/web/app/views/subscriptions/preview-change.pug
Normal file
11
services/web/app/views/subscriptions/preview-change.pug
Normal file
@@ -0,0 +1,11 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/preview-change'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-subscriptionChangePreview" data-type="json" content=changePreview)
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
#subscription-preview-change
|
@@ -0,0 +1,10 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/subtotal-limit-exceeded'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-groupName", data-type="string", content=groupName)
|
||||
|
||||
block content
|
||||
main.content.content-alt#subtotal-limit-exceeded-root
|
@@ -0,0 +1,12 @@
|
||||
extends ../layout-react
|
||||
|
||||
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)
|
||||
|
||||
block content
|
||||
main.content.content-alt#subscription-success-root
|
11
services/web/app/views/subscriptions/team/group-invites.pug
Normal file
11
services/web/app/views/subscriptions/team/group-invites.pug
Normal file
@@ -0,0 +1,11 @@
|
||||
extends ../../layout-react
|
||||
|
||||
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)
|
||||
|
||||
block content
|
||||
main.content.content-alt.team-invite#group-invites-root
|
18
services/web/app/views/subscriptions/team/invite-managed.pug
Normal file
18
services/web/app/views/subscriptions/team/invite-managed.pug
Normal file
@@ -0,0 +1,18 @@
|
||||
extends ../../layout-react
|
||||
|
||||
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)
|
||||
|
||||
block content
|
||||
main.content.content-alt.team-invite#invite-managed-root
|
17
services/web/app/views/subscriptions/team/invite.pug
Normal file
17
services/web/app/views/subscriptions/team/invite.pug
Normal file
@@ -0,0 +1,17 @@
|
||||
extends ../../layout-react
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/invite'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-hasIndividualRecurlySubscription" data-type="boolean" content=hasIndividualRecurlySubscription)
|
||||
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
|
@@ -0,0 +1,30 @@
|
||||
extends ../../layout-react
|
||||
|
||||
block append meta
|
||||
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
|
||||
.container
|
||||
.row
|
||||
div(class=colClass)
|
||||
.card.text-center
|
||||
.card-body
|
||||
.page-header
|
||||
// TODO: Remove `team-invite-name` once we fully migrated to Bootstrap 5
|
||||
h1.text-centered !{translate("invited_to_group", {inviterName: inviterName, appName: appName }, [{name: 'span', attrs: {class: 'team-invite-name'}}])}
|
||||
|
||||
if (accountExists)
|
||||
div
|
||||
p #{translate("invited_to_group_login_benefits", {appName: appName})}
|
||||
p #{translate("invited_to_group_login", {emailAddress: emailAddress})}
|
||||
p
|
||||
a.btn.btn-primary(href=`/login?redir=/subscription/invites/${inviteToken}${groupSSOActive ? "&hide_sso_login=true" : ""}`) #{translate("login_to_accept_invitation")}
|
||||
else
|
||||
div
|
||||
p #{translate("invited_to_group_register_benefits", {appName: appName})}
|
||||
p #{translate("invited_to_group_register", {inviterName: inviterName})}
|
||||
p
|
||||
a.btn.btn-primary(href=`/register?redir=/subscription/invites/${inviteToken}${groupSSOActive ? "&hide_sso_login=true" : ""}`) #{translate("register_to_accept_invitation")}
|
@@ -0,0 +1,12 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/upgrade-group-subscription'
|
||||
|
||||
block append meta
|
||||
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
|
15
services/web/app/views/user/accountSuspended.pug
Normal file
15
services/web/app/views/user/accountSuspended.pug
Normal file
@@ -0,0 +1,15 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- metadata.robotsNoindexNofollow = true
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container-custom-sm.mx-auto
|
||||
.card
|
||||
h3 #{translate('your_account_is_suspended')}
|
||||
p #{translate('sorry_this_account_has_been_suspended')}
|
||||
p !{translate('please_contact_us_if_you_think_this_is_in_error', {}, [{name: 'a', attrs: {href: `mailto:${settings.adminEmail}`}}])}
|
12
services/web/app/views/user/addSecondaryEmail.pug
Normal file
12
services/web/app/views/user/addSecondaryEmail.pug
Normal file
@@ -0,0 +1,12 @@
|
||||
extends ../layout-react
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressSkipToContent = true
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/add-secondary-email'
|
||||
|
||||
block content
|
||||
main.content.content-alt
|
||||
#add-secondary-email
|
13
services/web/app/views/user/compromised_password.pug
Normal file
13
services/web/app/views/user/compromised_password.pug
Normal file
@@ -0,0 +1,13 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressGoogleAnalytics = true
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/compromised-password'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
#compromised-password
|
15
services/web/app/views/user/confirmSecondaryEmail.pug
Normal file
15
services/web/app/views/user/confirmSecondaryEmail.pug
Normal file
@@ -0,0 +1,15 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressSkipToContent = true
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/confirm-secondary-email'
|
||||
|
||||
block append meta
|
||||
meta(name="ol-email" content=email)
|
||||
|
||||
block content
|
||||
main.content.content-alt
|
||||
#confirm-secondary-email
|
60
services/web/app/views/user/confirm_email.pug
Normal file
60
services/web/app/views/user/confirm_email.pug
Normal file
@@ -0,0 +1,60 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-8.col-md-offset-2.col-lg-6.col-lg-offset-3
|
||||
.card
|
||||
.page-header(data-ol-hide-on-error-message="confirm-email-wrong-user")
|
||||
h1 #{translate("confirm_email")}
|
||||
form(
|
||||
method="POST"
|
||||
action="/logout"
|
||||
id="logoutForm"
|
||||
)
|
||||
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)
|
||||
|
||||
div(data-ol-not-sent)
|
||||
+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.btn-block(
|
||||
form="logoutForm"
|
||||
) #{translate('log_in_with_a_different_account')}
|
||||
|
||||
.actions
|
||||
button.btn-primary.btn.btn-block(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight
|
||||
data-ol-hide-on-error-message="confirm-email-wrong-user"
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate('confirm')}
|
||||
span(hidden data-ol-inflight="pending")
|
||||
i.fa.fa-fw.fa-spin.fa-spinner(aria-hidden="true")
|
||||
| #{translate('confirming')}…
|
||||
|
||||
div(hidden data-ol-sent)
|
||||
.alert.alert-success
|
||||
| #{translate('thank_you_email_confirmed')}
|
||||
div.text-center
|
||||
a.btn.btn-primary(href="/user/settings")
|
||||
| #{translate('go_to_account_settings')}
|
49
services/web/app/views/user/email-preferences.pug
Normal file
49
services/web/app/views/user/email-preferences.pug
Normal file
@@ -0,0 +1,49 @@
|
||||
extends ../layout-marketing
|
||||
include ../_mixins/back_to_btns
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
|
||||
.card
|
||||
.page-header
|
||||
h1 #{translate("newsletter_info_title")}
|
||||
|
||||
p #{translate("newsletter_info_summary")}
|
||||
|
||||
- var submitAction
|
||||
if subscribed
|
||||
- submitAction = '/user/newsletter/unsubscribe'
|
||||
p !{translate("newsletter_info_subscribed", {}, ['strong'])}
|
||||
else
|
||||
- submitAction = '/user/newsletter/subscribe'
|
||||
p !{translate("newsletter_info_unsubscribed", {}, ['strong'])}
|
||||
|
||||
form(
|
||||
data-ol-async-form
|
||||
data-ol-reload-on-success
|
||||
name="newsletterForm"
|
||||
action=submitAction
|
||||
method="POST"
|
||||
)
|
||||
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")}…
|
||||
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")}…
|
||||
|
||||
if subscribed
|
||||
p #{translate("newsletter_info_note")}
|
||||
|
||||
.page-separator
|
||||
+back-to-btns()
|
52
services/web/app/views/user/login.pug
Normal file
52
services/web/app/views/user/login.pug
Normal file
@@ -0,0 +1,52 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-6.col-md-offset-3.col-lg-4.col-lg-offset-4
|
||||
.card
|
||||
.page-header
|
||||
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)
|
||||
+formMessages()
|
||||
+customFormMessage('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.sr-only(id='resetPasswordDescription')
|
||||
| #{translate('reset_password_link')}
|
||||
+customValidationMessage('password-compromised')
|
||||
| !{translate('password_compromised_try_again_or_use_known_device_or_reset', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com/passwords', rel: 'noopener noreferrer', target: '_blank'}}, {name: 'a', attrs: {href: '/user/password/reset', target: '_blank'}}])}.
|
||||
.form-group
|
||||
input.form-control(
|
||||
type='email',
|
||||
name='email',
|
||||
required,
|
||||
placeholder='email@example.com',
|
||||
autofocus="true"
|
||||
)
|
||||
.form-group
|
||||
input.form-control(
|
||||
type='password',
|
||||
name='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")}…
|
||||
a.pull-right(href='/user/password/reset') #{translate("forgot_your_password")}?
|
||||
if login_support_text
|
||||
hr
|
||||
p.text-center !{login_support_text}
|
||||
|
20
services/web/app/views/user/one_time_login.pug
Normal file
20
services/web/app/views/user/one_time_login.pug
Normal file
@@ -0,0 +1,20 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-6.col-md-offset-3.col-lg-4.col-lg-offset-4
|
||||
.card
|
||||
.page-header
|
||||
h1 We're back!
|
||||
p Overleaf is now running normally.
|
||||
p
|
||||
| Please
|
||||
|
|
||||
a(href="/login") log in
|
||||
|
|
||||
| to continue working on your projects.
|
76
services/web/app/views/user/passwordReset-bs5.pug
Normal file
76
services/web/app/views/user/passwordReset-bs5.pug
Normal file
@@ -0,0 +1,76 @@
|
||||
extends ../layout-website-redesign-bootstrap-5
|
||||
include ../_mixins/recaptcha
|
||||
include ../_mixins/notification
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
|
||||
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")
|
||||
div(
|
||||
id="recaptcha"
|
||||
class="g-recaptcha"
|
||||
data-sitekey=settings.recaptcha.siteKey
|
||||
data-size="invisible"
|
||||
data-badge="inline"
|
||||
)
|
||||
|
||||
main#main-content(data-ol-captcha-retry-trigger-area="")
|
||||
a.auth-aux-logo(href="/")
|
||||
img(src=buildImgPath("ol-brand/overleaf-o-dark.svg") alt=settings.appName)
|
||||
.auth-aux-container
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="passwordResetForm"
|
||||
action="/user/password/reset"
|
||||
method="POST"
|
||||
captcha=(showCaptcha ? '' : false)
|
||||
captcha-action-name=(showCaptcha ? "passwordReset" : 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")}
|
||||
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()
|
||||
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)
|
||||
.form-group.mb-3
|
||||
label.form-label(for='email') #{translate("email")}
|
||||
input.form-control#email(
|
||||
aria-label="email"
|
||||
type='email'
|
||||
name='email'
|
||||
required
|
||||
autocomplete="username"
|
||||
autofocus
|
||||
)
|
||||
.actions
|
||||
button.btn.btn-primary.w-100.mb-3(
|
||||
type='submit'
|
||||
data-ol-disabled-inflight
|
||||
aria-label=translate('reset_password_sentence_case')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate("reset_password_sentence_case")}
|
||||
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")}
|
||||
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')}
|
||||
|
||||
if showCaptcha
|
||||
+recaptchaConditions
|
84
services/web/app/views/user/passwordReset.pug
Normal file
84
services/web/app/views/user/passwordReset.pug
Normal file
@@ -0,0 +1,84 @@
|
||||
extends ../layout-marketing
|
||||
include ../_mixins/recaptcha
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
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")
|
||||
div(
|
||||
id="recaptcha"
|
||||
class="g-recaptcha"
|
||||
data-sitekey=settings.recaptcha.siteKey
|
||||
data-size="invisible"
|
||||
data-badge="inline"
|
||||
)
|
||||
|
||||
main.content.content-alt#main-content(data-ol-captcha-retry-trigger-area="")
|
||||
.container-custom-sm.mx-auto
|
||||
.card
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="passwordResetForm"
|
||||
action="/user/password/reset",
|
||||
method="POST",
|
||||
captcha=(showCaptcha ? '' : false),
|
||||
captcha-action-name=(showCaptcha ? "passwordReset" : 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")}
|
||||
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()
|
||||
if error && error !== 'password_reset_token_expired'
|
||||
div.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;")
|
||||
.notification-icon
|
||||
span.material-symbols.material-symbols-rounded(aria-hidden="true") 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)
|
||||
.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",
|
||||
autofocus
|
||||
)
|
||||
.actions
|
||||
button.btn.btn-primary.w-100(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight,
|
||||
aria-label=translate('request_password_reset_to_reconfirm')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate("request_password_reset")}
|
||||
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')}
|
||||
|
||||
if showCaptcha
|
||||
+recaptchaConditions
|
38
services/web/app/views/user/primaryEmailCheck-bs5.pug
Normal file
38
services/web/app/views/user/primaryEmailCheck-bs5.pug
Normal file
@@ -0,0 +1,38 @@
|
||||
extends ../layout-website-redesign-bootstrap-5
|
||||
|
||||
block content
|
||||
main#main-content
|
||||
.auth-aux-container
|
||||
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"
|
||||
)
|
||||
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")}…
|
||||
|
||||
a.btn.btn-secondary.w-100.mb-4(
|
||||
href="/user/settings#add-email"
|
||||
data-ol-slow-link
|
||||
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")}…
|
||||
p.small.mb-2
|
||||
| #{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' }}])}
|
42
services/web/app/views/user/primaryEmailCheck.pug
Normal file
42
services/web/app/views/user/primaryEmailCheck.pug
Normal file
@@ -0,0 +1,42 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.login-register-container.primary-email-check-container
|
||||
.card.primary-email-check-card
|
||||
img.primary-email-check-logo(src=buildImgPath("ol-brand/overleaf.svg") alt=settings.appName)
|
||||
h3.primary-email-check-header #{translate("keep_your_account_safe")}
|
||||
.login-register-form.primary-email-check-form(data-ol-multi-submit)
|
||||
p.small
|
||||
| !{translate("primary_email_check_question", { email: getUserEmail() }, ["strong"])}
|
||||
form(
|
||||
data-ol-async-form
|
||||
action="/user/emails/primary-email-check"
|
||||
method="POST"
|
||||
)
|
||||
input(name='_csrf', type='hidden', value=csrfToken)
|
||||
+formMessages()
|
||||
|
||||
button.btn-primary.btn.btn-block.btn-primary-email-check-button.primary-email-confirm-button(
|
||||
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-secondary.btn.btn-block.btn-primary-email-check-button.primary-email-change-button(
|
||||
href="/user/settings#add-email"
|
||||
data-ol-slow-link
|
||||
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")}…
|
||||
p.small
|
||||
| #{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' }}])}
|
69
services/web/app/views/user/reconfirm-bs5.pug
Normal file
69
services/web/app/views/user/reconfirm-bs5.pug
Normal file
@@ -0,0 +1,69 @@
|
||||
extends ../layout-website-redesign-bootstrap-5
|
||||
include ../_mixins/recaptcha
|
||||
|
||||
block content
|
||||
- var email = reconfirm_email ? reconfirm_email : ""
|
||||
- var showCaptcha = settings.recaptcha && settings.recaptcha.siteKey && !(settings.recaptcha.disabled && settings.recaptcha.disabled.passwordReset)
|
||||
|
||||
if showCaptcha
|
||||
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render=explicit")
|
||||
div(
|
||||
id="recaptcha"
|
||||
class="g-recaptcha"
|
||||
data-sitekey=settings.recaptcha.siteKey
|
||||
data-size="invisible"
|
||||
data-badge="inline"
|
||||
)
|
||||
|
||||
main#main-content(data-ol-captcha-retry-trigger-area="")
|
||||
.container.auth-aux-container(style="max-width: 420px;")
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="reconfirmAccountForm"
|
||||
action="/user/reconfirm"
|
||||
method="POST"
|
||||
aria-label=translate('request_reconfirmation_email')
|
||||
captcha=(showCaptcha ? '' : false)
|
||||
captcha-action-name=(showCaptcha ? "passwordReset" : false)
|
||||
)
|
||||
h1.h5.mb-3 #{translate("reconfirm_account")}
|
||||
p #{translate('reconfirm_explained')}
|
||||
|
|
||||
a(href=`mailto:${settings.adminEmail}`) #{settings.adminEmail}
|
||||
| .
|
||||
|
||||
div(data-ol-not-sent)
|
||||
+formMessagesNewStyle()
|
||||
|
||||
input(type="hidden" name="_csrf" value=csrfToken)
|
||||
.form-group.mb-3
|
||||
label.form-label(for='email') #{translate("please_enter_email")}
|
||||
input.form-control(
|
||||
aria-label="email"
|
||||
type='email'
|
||||
name='email'
|
||||
placeholder='email@example.com'
|
||||
required
|
||||
autofocus
|
||||
value=email
|
||||
)
|
||||
.actions
|
||||
button.btn.btn-primary.w-100(
|
||||
style="white-space: normal;"
|
||||
type='submit'
|
||||
data-ol-disabled-inflight
|
||||
aria-label=translate('request_password_reset_to_reconfirm')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate('request_password_reset_to_reconfirm')}
|
||||
span(hidden data-ol-inflight="pending")
|
||||
| #{translate('request_password_reset_to_reconfirm')}…
|
||||
div(hidden data-ol-sent)
|
||||
div.alert.alert-success(
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
span #{translate('password_reset_email_sent')}
|
||||
|
||||
if showCaptcha
|
||||
+recaptchaConditions
|
73
services/web/app/views/user/reconfirm.pug
Normal file
73
services/web/app/views/user/reconfirm.pug
Normal file
@@ -0,0 +1,73 @@
|
||||
extends ../layout-marketing
|
||||
include ../_mixins/recaptcha
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
- var email = reconfirm_email ? reconfirm_email : ""
|
||||
- var showCaptcha = settings.recaptcha && settings.recaptcha.siteKey && !(settings.recaptcha.disabled && settings.recaptcha.disabled.passwordReset)
|
||||
|
||||
if showCaptcha
|
||||
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render=explicit")
|
||||
div(
|
||||
id="recaptcha"
|
||||
class="g-recaptcha"
|
||||
data-sitekey=settings.recaptcha.siteKey
|
||||
data-size="invisible"
|
||||
data-badge="inline"
|
||||
)
|
||||
|
||||
main.content.content-alt#main-content(data-ol-captcha-retry-trigger-area="")
|
||||
.container
|
||||
.row
|
||||
.col-sm-12.col-md-6.col-md-offset-3
|
||||
.card
|
||||
h1.card-header.text-capitalize #{translate("reconfirm")} #{translate("Account")}
|
||||
p #{translate('reconfirm_explained')}
|
||||
a(href=`mailto:${settings.adminEmail}`) #{settings.adminEmail}
|
||||
| .
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="reconfirmAccountForm"
|
||||
action="/user/reconfirm",
|
||||
method="POST",
|
||||
aria-label=translate('request_reconfirmation_email')
|
||||
captcha=(showCaptcha ? '' : false),
|
||||
captcha-action-name=(showCaptcha ? "passwordReset" : false)
|
||||
)
|
||||
div(data-ol-not-sent)
|
||||
+formMessages()
|
||||
|
||||
input(type="hidden", name="_csrf", 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,
|
||||
autofocus
|
||||
value=email
|
||||
)
|
||||
.actions
|
||||
button.btn.btn-primary(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight,
|
||||
aria-label=translate('request_password_reset_to_reconfirm')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate('request_password_reset_to_reconfirm')}
|
||||
span(hidden data-ol-inflight="pending")
|
||||
| #{translate('request_password_reset_to_reconfirm')}…
|
||||
div(hidden data-ol-sent)
|
||||
div.alert.alert-success(
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
)
|
||||
span #{translate('password_reset_email_sent')}
|
||||
.row
|
||||
.col-sm-12.col-md-6.col-md-offset-3
|
||||
if showCaptcha
|
||||
+recaptchaConditions
|
35
services/web/app/views/user/register.pug
Normal file
35
services/web/app/views/user/register.pug
Normal file
@@ -0,0 +1,35 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.registration_message
|
||||
if sharedProjectData.user_first_name !== undefined
|
||||
h1 #{translate("user_wants_you_to_see_project", {username:sharedProjectData.user_first_name, projectname:""})}
|
||||
em #{sharedProjectData.project_name}
|
||||
div
|
||||
| #{translate("join_sl_to_view_project")}.
|
||||
div
|
||||
| #{translate("already_have_sl_account")}
|
||||
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")}
|
||||
|
||||
.row
|
||||
.col-md-8.col-md-offset-2.col-lg-6.col-lg-offset-3
|
||||
.card
|
||||
.page-header
|
||||
h1 #{translate("register")}
|
||||
p
|
||||
| Please contact
|
||||
|
|
||||
strong #{settings.adminEmail}
|
||||
|
|
||||
| to create an account.
|
16
services/web/app/views/user/restricted.pug
Normal file
16
services/web/app/views/user/restricted.pug
Normal file
@@ -0,0 +1,16 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-8.col-md-offset-2.text-center
|
||||
.page-header
|
||||
h2 #{translate("restricted_no_permission")}
|
||||
p
|
||||
a(href="/")
|
||||
i.fa.fa-arrow-circle-o-left(aria-hidden="true")
|
||||
| #{translate("take_me_home")}
|
72
services/web/app/views/user/sessions.pug
Normal file
72
services/web/app/views/user/sessions.pug
Normal file
@@ -0,0 +1,72 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.container
|
||||
.row
|
||||
.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
|
||||
.card.clear-user-sessions
|
||||
.page-header
|
||||
h1 #{translate("your_sessions")}
|
||||
|
||||
if currentSession.ip_address && currentSession.session_created
|
||||
h3 #{translate("current_session")}
|
||||
div
|
||||
table.table.table-striped
|
||||
thead
|
||||
tr
|
||||
th #{translate("ip_address")}
|
||||
th #{translate("session_created_at")}
|
||||
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'
|
||||
)
|
||||
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
|
||||
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"
|
||||
data-ol-disable-inflight
|
||||
)
|
||||
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
|
||||
a.btn.btn-secondary.text-capitalize(href='/user/settings') #{translate('back_to_account_settings')}
|
||||
|
|
||||
a.btn.btn-secondary.text-capitalize(href='/project') #{translate('back_to_your_projects')}
|
90
services/web/app/views/user/setPassword-bs5.pug
Normal file
90
services/web/app/views/user/setPassword-bs5.pug
Normal file
@@ -0,0 +1,90 @@
|
||||
extends ../layout-website-redesign-bootstrap-5
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
|
||||
block content
|
||||
main#main-content
|
||||
a.auth-aux-logo(href="/")
|
||||
img(src=buildImgPath("ol-brand/overleaf-o-dark.svg") alt=settings.appName)
|
||||
.auth-aux-container
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="passwordResetForm"
|
||||
action="/user/password/set"
|
||||
method="POST"
|
||||
data-ol-hide-on-error="token-expired"
|
||||
)
|
||||
div(
|
||||
hidden
|
||||
data-ol-sent
|
||||
)
|
||||
h1.h3.mb-3.mt-0 #{translate("password_updated")}
|
||||
p.mb-4 #{translate("your_password_has_been_successfully_changed")}.
|
||||
a.btn.btn-primary.w-100(href='/login') #{translate("log_in_now")}
|
||||
|
||||
div(data-ol-not-sent)
|
||||
h1.h3.mb-3.mt-0 #{translate("reset_your_password")}
|
||||
p(data-ol-hide-on-error-message="token-expired") #{translate("create_a_new_password_for_your_account")}.
|
||||
+formMessagesNewStyle()
|
||||
|
||||
+customFormMessageNewStyle('password-contains-email', 'danger')
|
||||
| #{translate('invalid_password_contains_email')}.
|
||||
| #{translate('use_a_different_password')}.
|
||||
|
||||
+customFormMessageNewStyle('password-too-similar', 'danger')
|
||||
| #{translate('invalid_password_too_similar')}.
|
||||
| #{translate('use_a_different_password')}.
|
||||
|
||||
+customFormMessageNewStyle('token-expired', 'danger')
|
||||
| #{translate('password_reset_token_expired')}
|
||||
br
|
||||
a(href="/user/password/reset")
|
||||
| #{translate('request_new_password_reset_email')}
|
||||
|
||||
input(type="hidden" name="_csrf" value=csrfToken)
|
||||
input(type="text" hidden name="email" autocomplete="username" value=email)
|
||||
|
||||
.form-group.mb-3
|
||||
label.form-label(for='passwordField', data-ol-hide-on-error-message="token-expired") #{translate("new_password")}
|
||||
input.form-control.auth-aux-new-password#passwordField(
|
||||
type='password'
|
||||
name='password'
|
||||
autocomplete="new-password"
|
||||
autofocus
|
||||
required
|
||||
minlength=settings.passwordStrengthOptions.length.min
|
||||
)
|
||||
|
||||
+customValidationMessageNewStyle('invalid-password')
|
||||
| #{translate('invalid_password')}.
|
||||
|
||||
+customValidationMessageNewStyle('password-must-be-different')
|
||||
| #{translate('password_cant_be_the_same_as_current_one')}.
|
||||
|
||||
+customValidationMessageNewStyle('password-must-be-strong')
|
||||
| !{translate('password_was_detected_on_a_public_list_of_known_compromised_passwords', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com/passwords', rel: 'noopener noreferrer', target: '_blank'}}])}.
|
||||
| #{translate('use_a_different_password')}.
|
||||
|
||||
input(
|
||||
type="hidden"
|
||||
name="passwordResetToken"
|
||||
value=passwordResetToken
|
||||
)
|
||||
div(data-ol-hide-on-error-message="token-expired")
|
||||
div #{translate('in_order_to_have_a_secure_account_make_sure_your_password')}
|
||||
ul.mb-3.ps-4
|
||||
li #{translate('is_longer_than_n_characters', {n: settings.passwordStrengthOptions.length.min})}
|
||||
li #{translate('does_not_contain_or_significantly_match_your_email')}
|
||||
li #{translate('is_not_used_on_any_other_website')}
|
||||
.actions
|
||||
button.btn.btn-primary.w-100(
|
||||
type='submit'
|
||||
data-ol-disabled-inflight
|
||||
aria-label=translate('set_new_password')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate('set_new_password')}
|
||||
span(hidden data-ol-inflight="pending")
|
||||
| #{translate('set_new_password')}…
|
89
services/web/app/views/user/setPassword.pug
Normal file
89
services/web/app/views/user/setPassword.pug
Normal file
@@ -0,0 +1,89 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.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"
|
||||
)
|
||||
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()
|
||||
|
||||
+customFormMessage('password-contains-email', 'danger')
|
||||
| #{translate('invalid_password_contains_email')}.
|
||||
| #{translate('use_a_different_password')}.
|
||||
|
||||
+customFormMessage('password-too-similar', 'danger')
|
||||
| #{translate('invalid_password_too_similar')}.
|
||||
| #{translate('use_a_different_password')}.
|
||||
|
||||
+customFormMessage('token-expired', 'danger')
|
||||
| #{translate('password_reset_token_expired')}
|
||||
br
|
||||
a(href="/user/password/reset")
|
||||
| #{translate('request_new_password_reset_email')}
|
||||
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
input(type="text" hidden name="email" autocomplete="username" value=email)
|
||||
|
||||
.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,
|
||||
minlength=settings.passwordStrengthOptions.length.min
|
||||
)
|
||||
|
||||
+customValidationMessage('invalid-password')
|
||||
| #{translate('invalid_password')}.
|
||||
|
||||
+customValidationMessage('password-must-be-different')
|
||||
| #{translate('password_cant_be_the_same_as_current_one')}.
|
||||
|
||||
+customValidationMessage('password-must-be-strong')
|
||||
| !{translate('password_was_detected_on_a_public_list_of_known_compromised_passwords', {}, [{name: 'a', attrs: {href: 'https://haveibeenpwned.com/passwords', rel: 'noopener noreferrer', target: '_blank'}}])}.
|
||||
| #{translate('use_a_different_password')}.
|
||||
|
||||
input(
|
||||
type="hidden",
|
||||
name="passwordResetToken",
|
||||
value=passwordResetToken
|
||||
)
|
||||
div(data-ol-hide-on-error-message="token-expired")
|
||||
div #{translate('in_order_to_have_a_secure_account_make_sure_your_password')}
|
||||
ul.mb-4.ps-4
|
||||
li #{translate('is_longer_than_n_characters', {n: settings.passwordStrengthOptions.length.min})}
|
||||
li #{translate('does_not_contain_or_significantly_match_your_email')}
|
||||
li #{translate('is_not_used_on_any_other_website')}
|
||||
.actions
|
||||
button.btn.btn-primary.w-100(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight
|
||||
aria-label=translate('set_new_password')
|
||||
)
|
||||
span(data-ol-inflight="idle")
|
||||
| #{translate('set_new_password')}
|
||||
span(hidden data-ol-inflight="pending")
|
||||
| #{translate('set_new_password')}…
|
38
services/web/app/views/user/settings.pug
Normal file
38
services/web/app/views/user/settings.pug
Normal file
@@ -0,0 +1,38 @@
|
||||
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-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)
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
#settings-page-root
|
@@ -0,0 +1,12 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/group-managers'
|
||||
|
||||
block append meta
|
||||
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
|
@@ -0,0 +1,17 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/group-members'
|
||||
|
||||
block append meta
|
||||
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-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
|
@@ -0,0 +1,12 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/institution-managers'
|
||||
|
||||
block append meta
|
||||
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
|
23
services/web/app/views/user_membership/new.pug
Normal file
23
services/web/app/views/user_membership/new.pug
Normal file
@@ -0,0 +1,23 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block vars
|
||||
- bootstrap5PageStatus = 'disabled'
|
||||
|
||||
block content
|
||||
main.content.content-alt#main-content
|
||||
.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.text-capitalize(
|
||||
type="submit",
|
||||
data-ol-disabled-inflight
|
||||
)
|
||||
span(data-ol-inflight="idle") Create #{entityName} in v2
|
||||
span(hidden data-ol-inflight="pending") #{translate("creating")}…
|
@@ -0,0 +1,12 @@
|
||||
extends ../layout-marketing
|
||||
|
||||
block entrypointVar
|
||||
- entrypoint = 'pages/user/subscription/group-management/publisher-managers'
|
||||
|
||||
block append meta
|
||||
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
|
Reference in New Issue
Block a user