diff --git a/services/web/app/views/subscriptions/plans-marketing/_mixins.pug b/services/web/app/views/subscriptions/plans-marketing/_mixins.pug index 0de46c8762..1ca50aa943 100644 --- a/services/web/app/views/subscriptions/plans-marketing/_mixins.pug +++ b/services/web/app/views/subscriptions/plans-marketing/_mixins.pug @@ -132,12 +132,20 @@ mixin gen_localized_price_for_plan_view(plan, view) data-ol-currencyCode=currencyCode ) #{settings.localizedPlanPricing[currencyCode][plan][view]} -mixin gen_localized_undiscounted_price_for_plan_view(plan, view) +mixin gen_localized_undiscounted_price_for_plan_view_personal(view) for currencyCode in Object.keys(settings.localizedPlanPricing) span( hidden=(currencyCode !== recommendedCurrency) data-ol-currencyCode=currencyCode - ) #{settings.localizedPlanPricing[currencyCode][plan]['withoutDiscount'][view]} + ) #{settings.localizedPlanPricing[currencyCode]['personal']['withoutDiscount'][view]} + +mixin gen_localized_undiscounted_price_for_plan_view(plan) + for currencyCode in Object.keys(settings.localizedPlanPricing) + span( + hidden=(currencyCode !== recommendedCurrency) + data-ol-currencyCode=currencyCode + ) #{settings.localizedPlanPricing[currencyCode][plan]['monthlyTimesTwelve']} + mixin gen_localized_price_for_plan(plan) div(data-ol-view='monthly') @@ -147,27 +155,38 @@ mixin gen_localized_price_for_plan(plan) +gen_localized_price_for_plan_view(plan, 'annual') span.small /yr -mixin gen_localized_undiscounted_price_for_plan(plan) +mixin gen_localized_undiscounted_price_for_plan_personal() div(data-ol-view='monthly') - .undiscounted-price.small + strike.undiscounted-price.small span.sr-only Price reduced from - +gen_localized_undiscounted_price_for_plan_view(plan, 'monthly') + +gen_localized_undiscounted_price_for_plan_view_personal('monthly') | /mo div(hidden data-ol-view='annual') - .undiscounted-price.small + strike.undiscounted-price.small span.sr-only Price reduced from - +gen_localized_undiscounted_price_for_plan_view(plan, 'annual') + +gen_localized_undiscounted_price_for_plan_view_personal('annual') + | /yr + +mixin gen_localized_undiscounted_price_for_plan(plan) + div(hidden data-ol-view='annual') + strike.undiscounted-price.small + span.sr-only Price reduced from + +gen_localized_undiscounted_price_for_plan_view(plan) | /yr //- Prices mixin price_personal +gen_localized_price_for_plan('personal') mixin price_personal_undiscounted - +gen_localized_undiscounted_price_for_plan('personal') + +gen_localized_undiscounted_price_for_plan_personal() mixin price_collaborator +gen_localized_price_for_plan('collaborator') +mixin price_collaborator_undiscounted + +gen_localized_undiscounted_price_for_plan('collaborator') mixin price_professional +gen_localized_price_for_plan('professional') +mixin price_professional_undiscounted + +gen_localized_undiscounted_price_for_plan('professional') mixin price_student_annual +gen_localized_price_for_plan_view('student', 'annual') span.small /yr @@ -199,15 +218,25 @@ mixin currency_dropdown ) #{currencyCode} #{settings.localizedPlanPricing[currencyCode]['symbol']} mixin plan_switch(location) - ul.nav.nav-pills + ul.nav.nav-pills(class=(location === 'card' ? "above-cards" : "")) li.active(data-ol-view-tab='monthly') a.btn.btn-default-outline( href="#" ) #{translate("monthly")} - li(data-ol-view-tab='annual') + li(data-ol-view-tab='annual' class=(location === 'card' ? "annual-saving-tooltip-container" : "")) a.btn.btn-default-outline( href="#" ) #{translate("annual")} + if (location === 'card') + .tooltip.in.bottom.annual-saving-tooltip( + role="tooltip" + data-ol-annual-saving-tooltip + ) + .tooltip-arrow + .tooltip-inner + span(data-ol-view="monthly") #{translate("save_20_percent_by_paying_annually")} + span(hidden data-ol-view="annual") #{translate("saving_20_percent")} + span(hidden data-ol-view="student") #{translate("save_20_percent_by_paying_annually")} li(data-ol-view-tab='student') a.btn.btn-default-outline( href="#" @@ -217,7 +246,7 @@ mixin allCardsAndControls(controlsRowSpaced, listLocation) - var location = listLocation ? 'card_' + listLocation : 'card' .row.top-switch(class=(controlsRowSpaced ? "row-spaced" : "")) .col-md-6.col-md-offset-3 - +plan_switch('card') + +plan_switch(location) .col-md-2.text-right +currency_dropdown @@ -250,6 +279,7 @@ mixin allCardsAndControls(controlsRowSpaced, listLocation) h5.tagline #{translate("tagline_collaborator")} .circle +price_collaborator + +price_collaborator_undiscounted +features_collaborator(location) .col-md-4 .card.card-last @@ -259,6 +289,7 @@ mixin allCardsAndControls(controlsRowSpaced, listLocation) h5.tagline #{translate("tagline_professional")} .circle +price_professional + +price_professional_undiscounted +features_professional(location) .card-group.text-centered(hidden data-ol-view='student') diff --git a/services/web/frontend/js/pages/user/subscription/plans.js b/services/web/frontend/js/pages/user/subscription/plans.js index 2a2c7b6091..ecb7c8cde1 100644 --- a/services/web/frontend/js/pages/user/subscription/plans.js +++ b/services/web/frontend/js/pages/user/subscription/plans.js @@ -1,6 +1,5 @@ import '../../../marketing' import '../../../features/plans/group-plan-modal' - import * as eventTracking from '../../../infrastructure/event-tracking' import getMeta from '../../../utils/meta' @@ -18,6 +17,7 @@ function selectView(view) { document.querySelectorAll('[data-ol-view]').forEach(el => { el.hidden = el.getAttribute('data-ol-view') !== view }) + updateAnnualSavingBanner(view) currentView = view updateLinkTargets() } @@ -81,6 +81,16 @@ function updateLinkTargets() { }) } +function updateAnnualSavingBanner(view) { + const tooltipEl = document.querySelector('[data-ol-annual-saving-tooltip]') + + if (view === 'annual') { + tooltipEl.classList.add('annual-selected') + } else { + tooltipEl.classList.remove('annual-selected') + } +} + function selectViewFromHash() { try { const params = new URLSearchParams(window.location.hash.substring(1)) diff --git a/services/web/frontend/stylesheets/app/plans.less b/services/web/frontend/stylesheets/app/plans.less index 0e2215675a..d9b8284608 100644 --- a/services/web/frontend/stylesheets/app/plans.less +++ b/services/web/frontend/stylesheets/app/plans.less @@ -85,7 +85,7 @@ font-size: @font-size-base * 0.8; } .undiscounted-price { - text-decoration: line-through; + display: block; margin-top: -48px; } } @@ -135,14 +135,42 @@ ul.nav-pills { text-align: center; margin-bottom: @line-height-computed; + display: flex; + justify-content: center; li { float: none; display: inline-block; + position: relative; + .annual-saving-tooltip { + white-space: nowrap; + left: 50%; + width: 200px; + margin-left: -100px; + &.bottom { + margin-top: 0px; + } + &.annual-selected { + width: 94px; + margin-left: -47px; + .tooltip-inner { + background-color: @ol-green; + } + .tooltip-arrow { + border-bottom-color: @ol-green; + } + } + .tooltip-inner { + max-width: none; + } + } } > li + li { margin-left: @line-height-computed / 2; } } + ul.nav-pills.above-cards { + margin-bottom: @line-height-computed * 2; + } } #changePlanSection { @@ -210,6 +238,19 @@ } } } +@media (max-width: @screen-xs-max) { + .plans ul.nav-pills { + li { + a { + font-size: @font-size-small; + padding: 8px 10px; + } + } + > li + li { + margin-left: @margin-sm; + } + } +} @media (min-width: @screen-md-min) { .plans { blockquote { diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 6d84404135..37ed9cc460 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1640,5 +1640,7 @@ "change_primary_email_address_instructions": "To change your primary email, please add your new primary email address first (by clicking <0>Add another email) and confirm it. Then click the <0>Make Primary button. <1>Learn more about managing your __appName__ emails.", "help_improve_overleaf_fill_out_this_survey": "If you would like to help us improve Overleaf, please take a moment to fill out <0>this survey.", "unlink_dropbox_folder": "Unlink Dropbox Account", - "unlink_dropbox_warning": "Any projects that you have synced with Dropbox will be disconnected and no longer kept in sync with Dropbox. Are you sure you want to unlink your Dropbox account?" + "unlink_dropbox_warning": "Any projects that you have synced with Dropbox will be disconnected and no longer kept in sync with Dropbox. Are you sure you want to unlink your Dropbox account?", + "save_20_percent_by_paying_annually": "Save 20% by paying annually", + "saving_20_percent": "Saving 20%!" }