Add new fat footer (#6260)

GitOrigin-RevId: 64c50caac2ec8d56b3f49d6f97c8a1c4d4b3a496
This commit is contained in:
Alf Eaton 2022-03-01 14:28:01 +00:00 committed by Copybot
parent cdf88358d4
commit 4610734f07
14 changed files with 417 additions and 64 deletions

View file

@ -613,6 +613,7 @@ const ProjectController = {
zipFileSizeLimit: Settings.maxUploadSize, zipFileSizeLimit: Settings.maxUploadSize,
isOverleaf: !!Settings.overleaf, isOverleaf: !!Settings.overleaf,
metadata: { viewport: false }, metadata: { viewport: false },
showThinFooter: true, // don't show the fat footer on the projects dashboard, as there's a fixed space available
} }
const paidUser = const paidUser =

View file

@ -355,6 +355,11 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
next() next()
}) })
webRouter.use(function (req, res, next) {
res.locals.showThinFooter = !Features.hasFeature('saas')
next()
})
webRouter.use(function (req, res, next) { webRouter.use(function (req, res, next) {
res.locals.ExposedSettings = { res.locals.ExposedSettings = {
isOverleaf: Settings.overleaf != null, isOverleaf: Settings.overleaf != null,

View file

@ -99,7 +99,7 @@ html(
block head-scripts block head-scripts
body body(class=(showThinFooter ? 'thin-footer' : undefined))
if(settings.recaptcha && settings.recaptcha.siteKeyV3) if(settings.recaptcha && settings.recaptcha.siteKeyV3)
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render="+settings.recaptcha.siteKeyV3) script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render="+settings.recaptcha.siteKeyV3)
@ -112,7 +112,10 @@ html(
block content block content
if (typeof(suppressFooter) == "undefined") if (typeof(suppressFooter) == "undefined")
include layout/footer-marketing if showThinFooter
include layout/footer-marketing
else
include layout/fat-footer
!= moduleIncludes("contactModal-marketing", locals) != moduleIncludes("contactModal-marketing", locals)

View file

@ -100,7 +100,7 @@ html(
block head-scripts block head-scripts
body(ng-csp=(cspEnabled ? "no-unsafe-eval" : false)) body(ng-csp=(cspEnabled ? "no-unsafe-eval" : false) class=(showThinFooter ? 'thin-footer' : undefined))
if(settings.recaptcha && settings.recaptcha.siteKeyV3) if(settings.recaptcha && settings.recaptcha.siteKeyV3)
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render="+settings.recaptcha.siteKeyV3) script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render="+settings.recaptcha.siteKeyV3)
@ -113,7 +113,10 @@ html(
block content block content
if (typeof(suppressFooter) == "undefined") if (typeof(suppressFooter) == "undefined")
include layout/footer if showThinFooter
include layout/footer
else
include layout/fat-footer
!= moduleIncludes("contactModal", locals) != moduleIncludes("contactModal", locals)

View file

@ -0,0 +1,18 @@
.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')}
ul.fat-footer-base-item.list-unstyled.fat-footer-base-language
include language-picker
.fat-footer-base-section.fat-footer-base-social
.fat-footer-base-item
a.fat-footer-social(href="https://twitter.com/overleaf")
i.fa.fa-twitter-square(aria-hidden="true")
.sr-only Overleaf on Twitter
a.fat-footer-social(href="https://www.facebook.com/overleaf.editor")
i.fa.fa-facebook-square(aria-hidden="true")
.sr-only Overleaf on Facebook
a.fat-footer-social(href="https://www.linkedin.com/company/writelatex-limited")
i.fa.fa-linkedin-square(aria-hidden="true")
.sr-only Overleaf on LinkedIn

View file

@ -0,0 +1,79 @@
footer.fat-footer.hidden-print
.fat-footer-container
.fat-footer-sections(class=hideFatFooter ? 'hidden' : undefined)
.footer-section#footer-brand
a(href='/', aria-label=settings.appName).footer-brand
.footer-section
.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="https://apply.workable.com/overleaf/") #{translate('careers')}
li
a(href="/for/press") #{translate('press_and_awards')}
li
a(href="/blog") #{translate('blog')}
.footer-section
.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
.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") #{translate('for_individuals_and_groups')}
li
a(href="/for/enterprises") #{translate('for_enterprise')}
li
a(href="/for/universities") #{translate('for_universities')}
li
a(href="/user/subscription/plans#view=student") #{translate('for_students')}
.footer-section
.footer-section-heading #{translate('get_involved')}
ul.list-unstyled
li
a(href="/for/community/advisors") #{translate('become_an_advisor')}
li
a(href="https://calendly.com/overleaf/user-research") #{translate('participate_in_user_research')}
if user
li
a(href="/beta/participate") #{translate('join_beta_program')}
li
a(href="/user/bonus") #{translate('refer_a_friend')}
.footer-section
.footer-section-heading #{translate('help')}
ul.list-unstyled
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

View file

@ -17,27 +17,7 @@ footer.site-footer
strong.text-muted | strong.text-muted |
if showLanguagePicker if showLanguagePicker
li.dropdown.dropup.subdued include language-picker
a.dropdown-toggle(
href="#",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false",
aria-label="Select " + translate('language'),
data-ol-lang-selector-tooltip,
title=translate('language')
)
i.fa.fa-fw.fa-language
|
| #{settings.translatedLanguages[currentLngCode]}
ul.dropdown-menu(role="menu")
li.dropdown-header #{translate("language")}
each subdomainDetails, subdomain in settings.i18n.subdomainLang
if !subdomainDetails.hide
li.lngOption
a.menu-indent(href=subdomainDetails.url+currentUrlWithQueryParams)
| #{settings.translatedLanguages[subdomainDetails.lngCode]}
if showLanguagePicker && hasCustomLeftNav if showLanguagePicker && hasCustomLeftNav
li li
@ -51,7 +31,6 @@ footer.site-footer
| !{item.text} | !{item.text}
ul.col-md-3.text-right ul.col-md-3.text-right
each item in nav.right_footer each item in nav.right_footer
li(ng-non-bindable) li(ng-non-bindable)
if item.url if item.url

View file

@ -6,10 +6,9 @@ footer.site-footer
.site-footer-content.hidden-print .site-footer-content.hidden-print
.row .row
ul.col-md-9 ul.col-md-9
if hasFeature('saas') if !settings.nav.hide_powered_by
li © #{new Date().getFullYear()} Overleaf
else if !settings.nav.hide_powered_by
li li
//- year of Server Pro release, static
| © 2021 | © 2021
| |
a(href='https://www.overleaf.com/for/enterprises') Powered by Overleaf a(href='https://www.overleaf.com/for/enterprises') Powered by Overleaf
@ -19,27 +18,7 @@ footer.site-footer
strong.text-muted | strong.text-muted |
if showLanguagePicker if showLanguagePicker
li.dropdown.dropup.subdued(dropdown) include language-picker
a.dropdown-toggle(
href="#",
dropdown-toggle,
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false",
aria-label="Select " + translate('language')
tooltip=translate('language')
)
i.fa.fa-fw.fa-language
|
| #{settings.translatedLanguages[currentLngCode]}
ul.dropdown-menu
li.dropdown-header #{translate("language")}
each subdomainDetails, subdomain in settings.i18n.subdomainLang
if !subdomainDetails.hide
li.lngOption
a.menu-indent(href=subdomainDetails.url+currentUrlWithQueryParams)
| #{settings.translatedLanguages[subdomainDetails.lngCode]}
if showLanguagePicker && hasCustomLeftNav if showLanguagePicker && hasCustomLeftNav
li li

View file

@ -0,0 +1,23 @@
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')
)
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.lngOption
a.menu-indent(href=subdomainDetails.url+currentUrlWithQueryParams role="menuitem")
| #{settings.translatedLanguages[subdomainDetails.lngCode]}

View file

@ -7,24 +7,28 @@ import getMeta from '../../../utils/meta'
let currentView = 'monthly' let currentView = 'monthly'
let currentCurrencyCode = getMeta('ol-recommendedCurrency') let currentCurrencyCode = getMeta('ol-recommendedCurrency')
function selectView(view) {
document.querySelectorAll('[data-ol-view-tab]').forEach(el => {
if (el.getAttribute('data-ol-view-tab') === view) {
el.classList.add('active')
} else {
el.classList.remove('active')
}
})
document.querySelectorAll('[data-ol-view]').forEach(el => {
el.hidden = el.getAttribute('data-ol-view') !== view
})
currentView = view
updateLinkTargets()
}
function setUpViewSwitching(liEl) { function setUpViewSwitching(liEl) {
const view = liEl.getAttribute('data-ol-view-tab') const view = liEl.getAttribute('data-ol-view-tab')
liEl.querySelector('a').addEventListener('click', function (e) { liEl.querySelector('a').addEventListener('click', function (e) {
e.preventDefault() e.preventDefault()
eventTracking.send('subscription-funnel', 'plans-page', `${view}-prices`) // deprecated by plans-page-toggle eventTracking.send('subscription-funnel', 'plans-page', `${view}-prices`)
eventTracking.sendMB('plans-page-toggle', { button: view }) eventTracking.sendMB('plans-page-toggle', { button: view })
document.querySelectorAll('[data-ol-view-tab]').forEach(el => { selectView(view)
if (el.getAttribute('data-ol-view-tab') === view) {
el.classList.add('active')
} else {
el.classList.remove('active')
}
})
document.querySelectorAll('[data-ol-view]').forEach(el => {
el.hidden = el.getAttribute('data-ol-view') !== view
})
currentView = view
updateLinkTargets()
}) })
} }
@ -77,6 +81,23 @@ function updateLinkTargets() {
}) })
} }
function selectViewFromHash() {
try {
const params = new URLSearchParams(window.location.hash.substring(1))
const view = params.get('view')
if (view) {
// make sure the selected view is valid
if (document.querySelector(`[data-ol-view-tab="${view}"]`)) {
selectView(view)
// clear the hash so it doesn't persist when switching plans
window.location.hash = ''
}
}
} catch {
// do nothing
}
}
document.querySelectorAll('[data-ol-view-tab]').forEach(setUpViewSwitching) document.querySelectorAll('[data-ol-view-tab]').forEach(setUpViewSwitching)
document document
.querySelectorAll('[data-ol-currencyCode-switch]') .querySelectorAll('[data-ol-currencyCode-switch]')
@ -85,3 +106,6 @@ document
.querySelectorAll('[data-ol-start-new-subscription]') .querySelectorAll('[data-ol-start-new-subscription]')
.forEach(setUpSubscriptionTracking) .forEach(setUpSubscriptionTracking)
updateLinkTargets() updateLinkTargets()
selectViewFromHash()
window.addEventListener('hashchange', selectViewFromHash)

View file

@ -50,3 +50,215 @@ footer.site-footer {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
} }
.fat-footer {
background: @ol-blue-gray-6;
color: @ol-blue-gray-1;
display: flex;
flex-direction: column;
.fat-footer-container {
margin: @margin-xxl auto;
}
a {
color: @ol-blue-gray-1;
}
.footer-brand-container {
flex: 1;
}
.fat-footer-sections {
display: grid;
column-gap: @margin-md;
padding: 0 @padding-md @padding-md;
}
.footer-brand {
display: block;
height: 37px; /* TODO: configurable? */
width: @navbar-brand-width;
background-image: @navbar-brand-image-url;
background-size: contain;
background-repeat: no-repeat;
background-position: left center;
}
.footer-section-heading {
font-family: @font-family-serif;
font-size: @font-size-h3;
line-height: @headings-line-height;
margin-bottom: @margin-md;
margin-top: @margin-md;
}
.footer-section ul {
font-family: @font-family-sans-serif;
font-size: @font-size-base;
line-height: @line-height-small;
}
.footer-section li {
padding-bottom: @padding-sm;
}
#footer-brand {
grid-column: ~'1/-1';
margin-top: @margin-md;
}
.fat-footer-base {
color: @ol-blue-gray-2;
font-size: @font-size-small;
line-height: @line-height-base;
.fat-footer-base-meta a:not(.dropdown-toggle) {
color: inherit;
}
.language-picker .dropdown-menu {
.dropdown-header {
display: none; /* hiding rather than removing as still needed in the thin footer */
}
a {
color: @gray-dark;
&:hover {
color: white;
}
}
}
}
.fat-footer-base-item {
display: flex;
white-space: nowrap;
}
@media (max-width: @screen-xs-max) {
.fat-footer-sections {
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(4, auto);
}
.fat-footer-base {
display: flex;
flex-direction: column;
align-items: center;
margin: @margin-md auto 0;
.fat-footer-base-section {
display: flex;
align-items: center;
}
.fat-footer-base-social {
order: 1;
}
.fat-footer-base-meta {
display: flex;
flex-direction: column-reverse;
align-items: center;
order: 2;
}
.fat-footer-base-item {
padding: @padding-xs;
margin: @margin-lg / 2;
}
.fat-footer-base-meta .fat-footer-base-item {
gap: @margin-lg;
}
.fat-footer-base-social .fat-footer-base-item {
gap: @margin-md;
}
.fat-footer-social {
font-size: @fat-footer-social-font-size;
}
.fat-footer-base-copyright {
order: 2;
}
}
}
@media (min-width: @screen-sm-min) {
.fat-footer-container {
width: (@screen-sm - (@padding-sm * 2));
}
#footer-brand {
grid-column: auto;
grid-row: ~'1/-1';
}
.fat-footer-sections {
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(2, auto);
}
.footer-section:last-of-type {
grid-column: 4;
}
.footer-section ul {
line-height: 20px;
}
.fat-footer-base {
display: flex;
justify-content: space-between;
margin: @margin-md auto;
.fat-footer-base-section {
display: flex;
align-items: center;
}
.fat-footer-base-item {
padding: @padding-xs;
margin: @margin-xs;
}
.fat-footer-base-meta .fat-footer-base-item {
gap: @margin-md;
}
.fat-footer-social {
margin: 0 @margin-xs;
font-size: @fat-footer-social-font-size;
}
}
}
@media (min-width: @screen-md-min) {
.fat-footer-container {
width: (@screen-md - @padding-md);
}
.fat-footer-sections {
grid-template-columns: repeat(4, 1fr);
}
}
@media (min-width: @screen-lg-min) {
.fat-footer-container {
width: (@screen-lg - @padding-lg);
}
.fat-footer-sections {
grid-template-columns: repeat(6, 1fr);
grid-template-rows: auto;
}
.footer-section:last-of-type {
grid-column: 6;
}
}
}

View file

@ -31,11 +31,14 @@ body {
background-color: @body-bg; background-color: @body-bg;
min-height: 100%; min-height: 100%;
position: relative; position: relative;
padding-bottom: @footer-height;
& > .content { & > .content {
min-height: calc(~'100vh -' @footer-height); min-height: calc(~'100vh -' @footer-height);
padding-top: @header-height + @content-margin-vertical; padding-top: @header-height + @content-margin-vertical;
} }
.thin-footer {
padding-bottom: @footer-height;
}
} }
// Reset fonts for relevant elements // Reset fonts for relevant elements

View file

@ -969,6 +969,7 @@
@footer-link-hover-color: @link-hover-color-alt; @footer-link-hover-color: @link-hover-color-alt;
@footer-bg-color: #fff; @footer-bg-color: #fff;
@footer-padding: 2em 0; @footer-padding: 2em 0;
@fat-footer-social-font-size: 30px;
// Editor header // Editor header
@ide-body-top-offset: 40px; @ide-body-top-offset: 40px;

View file

@ -832,6 +832,29 @@
"Terms": "Terms", "Terms": "Terms",
"Security": "Security", "Security": "Security",
"About": "About", "About": "About",
"learn": "Learn",
"latex_in_thirty_minutes": "LaTeX in 30 minutes",
"how_to_insert_images": "How to insert images",
"how_to_create_tables": "How to create tables",
"for_individuals_and_groups": "For individuals & groups",
"for_enterprise": "For enterprise",
"for_universities": "For universities",
"for_students": "For students",
"get_involved": "Get involved",
"become_an_advisor": "Become an __appName__ advisor",
"participate_in_user_research": "Participate in user research",
"join_beta_program": "Join beta program",
"refer_a_friend": "Refer a friend",
"webinars": "Webinars",
"tutorials": "Tutorials",
"footer_plans_and_pricing": "Plans & pricing",
"footer_contact_us": "Contact us",
"website_status": "Website status",
"privacy_and_terms": "Privacy and Terms",
"footer_about_us": "About us",
"our_values": "Our values",
"careers": "Careers",
"press_and_awards": "Press & awards",
"editor_disconected_click_to_reconnect": "Editor disconnected, click anywhere to reconnect.", "editor_disconected_click_to_reconnect": "Editor disconnected, click anywhere to reconnect.",
"word_count": "Word Count", "word_count": "Word Count",
"please_compile_pdf_before_word_count": "Please compile your project before performing a word count", "please_compile_pdf_before_word_count": "Please compile your project before performing a word count",