From 920e86e4d09b2b56a72c304e8d8b9db38f0e17df Mon Sep 17 00:00:00 2001 From: M Fahru Date: Fri, 1 Mar 2024 06:11:25 -0700 Subject: [PATCH] Merge pull request #17303 from overleaf/mf-fix-plans-page-mobile [web] Fix plans page table styling on both desktop and mobile GitOrigin-RevId: 252bbaf7245751b1cfe07286a0fe19069219bb5b --- .../src/Features/Subscription/plansConfig.js | 7 +- .../app/views/subscriptions/plans/_mixins.pug | 31 ++-- .../stylesheets/app/{ => plans}/plans-ol.less | 0 .../stylesheets/app/{ => plans}/plans-v2.less | 156 ++++++------------ .../stylesheets/app/{ => plans}/plans.less | 0 .../web/frontend/stylesheets/main-style.less | 6 +- 6 files changed, 69 insertions(+), 131 deletions(-) rename services/web/frontend/stylesheets/app/{ => plans}/plans-ol.less (100%) rename services/web/frontend/stylesheets/app/{ => plans}/plans-v2.less (89%) rename services/web/frontend/stylesheets/app/{ => plans}/plans.less (100%) diff --git a/services/web/app/src/Features/Subscription/plansConfig.js b/services/web/app/src/Features/Subscription/plansConfig.js index f2257b75cd..f7fbe38477 100644 --- a/services/web/app/src/Features/Subscription/plansConfig.js +++ b/services/web/app/src/Features/Subscription/plansConfig.js @@ -20,6 +20,7 @@ const config = { additionalEventSegmentation: {}, }, group: { + maxColumn: 3, tableHead: { group_collaborator: {}, group_professional: {}, @@ -36,15 +37,15 @@ const config = { additionalEventSegmentation: {}, }, student: { - baseColspan: 2, + baseColspan: 1, maxColumn: 3, tableHead: { student_free: { - colspan: 3, + colspan: 1, }, student_student: { showExtraContent: false, - colspan: 3, + colspan: 1, }, }, features: plansFeatures.student, diff --git a/services/web/app/views/subscriptions/plans/_mixins.pug b/services/web/app/views/subscriptions/plans/_mixins.pug index 0e472fd238..8712097f55 100644 --- a/services/web/app/views/subscriptions/plans/_mixins.pug +++ b/services/web/app/views/subscriptions/plans/_mixins.pug @@ -13,21 +13,18 @@ mixin gen_localized_price_for_plan_view(plan, view) mixin plans_v2_table(period, config) - var baseColspan = config.baseColspan || 1 - var maxColumn = config.maxColumn || 4 - - var discountedColumn = config.discountedColumn || {} - tr(class=`cols-${maxColumn}`) + - var tableHeadKeys = Object.keys(config.tableHead) + tr(class=`plans-v2-table-cols-${tableHeadKeys.length}`) th(colspan=baseColspan) - for (var i = 0; i < maxColumn; i++) - - var tableHeadKey = Object.keys(config.tableHead)[i] + - var tableHeadKey = tableHeadKeys[i] - var tableHeadOptions = Object.values(config.tableHead)[i] || {} - var colspan = tableHeadOptions.colspan || baseColspan - var highlighted = i === config.highlightedColumn.index - - var discountHighlighted = i === discountedColumn.index - var eventTrackingKey = config.eventTrackingKey - var additionalEventSegmentation = config.additionalEventSegmentation || {} - - if (discountHighlighted) { - var thClass = 'plans-v2-table-discount-highlighted' - } else if (highlighted) { + if (highlighted) { var thClass = 'plans-v2-table-green-highlighted' } else if (i === config.highlightedColumn.index - 1) { var thClass = 'plans-v2-table-cell-before-green-highlighted-column' @@ -69,8 +66,6 @@ mixin plans_v2_table(period, config) scope=scopeValue ) .plans-v2-table-th - if (discountHighlighted) - p.plans-v2-table-discount-highlighted-text #{translate(config.discountedColumn.text[period]).toUpperCase()} if (highlighted) p.plans-v2-table-green-highlighted-text #{translate(config.highlightedColumn.text[period]).toUpperCase()} case tableHeadKey @@ -121,7 +116,7 @@ mixin plans_v2_table(period, config) span.sr-only #{translate(featuresPerSection.dividerInfo)} for feature, featureIndex in featuresPerSection.items tr( - class=(featureIndex === (featuresPerSection.items.length - 1) ? `plans-v2-table-row-last-row-per-section cols-${maxColumn}` : `cols-${maxColumn}`) + class=(featureIndex === (featuresPerSection.items.length - 1) ? `plans-v2-table-row-last-row-per-section plans-v2-table-cols-${tableHeadKeys.length}` : `plans-v2-table-cols-${tableHeadKeys.length}`) ) th( class="plans-v2-table-row-header" @@ -157,9 +152,7 @@ mixin plans_v2_table(period, config) - var tableHeadOptions = Object.values(config.tableHead)[planIndex] || {} - var colspan = tableHeadOptions.colspan || baseColspan - - if (planIndex === discountedColumn.index) { - var tdClass = 'plans-v2-table-discount-highlighted' - } else if (planIndex === config.highlightedColumn.index) { + if (planIndex === config.highlightedColumn.index) { var tdClass = 'plans-v2-table-green-highlighted' } else if (planIndex === config.highlightedColumn.index - 1) { var tdClass = 'plans-v2-table-cell-before-green-highlighted-column' @@ -417,12 +410,12 @@ mixin group_plans_license_picker() span ) span.sr-only #{translate("apply_educational_discount_info")} -mixin btn_buy_individual(highlighted, discountHighlighted, eventTrackingKey, subscriptionPlan, period) +mixin btn_buy_individual(highlighted, eventTrackingKey, subscriptionPlan, period) a.btn.plans-v2-table-btn-buy( data-ol-start-new-subscription=subscriptionPlan data-ol-event-tracking-key=eventTrackingKey data-ol-item-view=period - class=(discountHighlighted ? 'btn-dark-blue' : (highlighted ? 'btn-primary' : 'btn-default')) + class=(highlighted ? 'btn-primary' : 'btn-default') ) if (period === 'monthly') span #{translate("try_for_free")} @@ -443,12 +436,12 @@ mixin btn_buy_individual_free() ) mixin btn_buy_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period) - +btn_buy_individual(highlighted, false, eventTrackingKey, 'collaborator', period) + +btn_buy_individual(highlighted, eventTrackingKey, 'collaborator', period) if (period === 'monthly') +additional_link_buy(eventTrackingKey, additionalEventSegmentation, 'collaborator', period) mixin btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period) - +btn_buy_individual(highlighted, false, eventTrackingKey, 'professional', period) + +btn_buy_individual(highlighted, eventTrackingKey, 'professional', period) if (period === 'monthly') +additional_link_buy(eventTrackingKey, additionalEventSegmentation, 'professional', period) @@ -565,9 +558,7 @@ mixin plans_v2_table_sticky_header(withSwitch, config) - var tableHeadKey = tableHeadKeys[i] - var translateKey = tableHeadKey.split('_')[1] - - if (config.discountedColumn?.index === i) { - var elClass = 'plans-v2-table-sticky-header-item-discount-highlighted' - } else if (config.highlightedColumn.index === i) { + if (config.highlightedColumn.index === i) { var elClass = 'plans-v2-table-sticky-header-item-green-highlighted' } else { var elClass = '' diff --git a/services/web/frontend/stylesheets/app/plans-ol.less b/services/web/frontend/stylesheets/app/plans/plans-ol.less similarity index 100% rename from services/web/frontend/stylesheets/app/plans-ol.less rename to services/web/frontend/stylesheets/app/plans/plans-ol.less diff --git a/services/web/frontend/stylesheets/app/plans-v2.less b/services/web/frontend/stylesheets/app/plans/plans-v2.less similarity index 89% rename from services/web/frontend/stylesheets/app/plans-v2.less rename to services/web/frontend/stylesheets/app/plans/plans-v2.less index 389c398db3..8251446779 100644 --- a/services/web/frontend/stylesheets/app/plans-v2.less +++ b/services/web/frontend/stylesheets/app/plans/plans-v2.less @@ -7,9 +7,7 @@ @plans-v2-highlighted-text-height-mobile: 41px; @plans-v2-learn-more-link-color: hsl(206, 100%, 52%); @plans-v2-top-switch-group-width-mobile: 46%; -@plans-v2-discount-highlighted-text-z-index: 2; @plans-v2-table-border-radius: 20px; -@plans-v2-dark-blue: #2857a1; @plans-v2-table-td-mobile-min-height: 34px; .plans { @@ -18,11 +16,6 @@ display: none; } } - - .btn-dark-blue { - background-color: @plans-v2-dark-blue; - color: @white; - } } .plans-v2-top-switch ul.plans-v2-nav { @@ -404,7 +397,6 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { } } -.plans-v2-table-group, .plans-v2-table-student { tr { // "hide" the last column on desktop by making the background-color as the default background color @@ -459,7 +451,7 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { } @media (max-width: @screen-md-max) { - tr { + tr:first-of-type { th:last-of-type { // Last column is only a UI placeholder for desktop view. // We need to hide it for mobile to have the full table fully visible on mobile @@ -468,21 +460,6 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { } } } - - @media (max-width: @screen-xs-max) { - tr { - &:not(.plans-v2-table-divider) { - td:not(:first-of-type), - th:not(:first-of-type) { - // 33.33% is because table-group & table-student have 3 real column on mobile. - // It actually has 5 table column, but on mobile version, - // the first column become row and the last column is hidden since it is just a UI placeholder. - // We need to force 33.33% width to make each of 3 columns have an equal width of 1/3 screen width. - width: 33.33%; - } - } - } - } } .plans-v2-table-individual { @@ -535,29 +512,6 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { } } } - - // for remove-personal-plan split test default variant - @media (max-width: @screen-xs-max) { - tr.cols-4:not(.plans-v2-table-divider) { - td, - th:not(:first-of-type) { - // 25% is because table-individual have 4 real columns on mobile - // it actually has 5 table columns, but on mobile version, the first column become row - // we need to force 25% width to make each of 4 columns have an equal width of 1/4 screen width - width: 25%; - } - } - // for remove-personal-plan split test personal-off variant - tr.cols-3:not(.plans-v2-table-divider) { - td:not(:first-of-type), - th:not(:first-of-type) { - // 33% is because table-individual have 3 real columns on mobile - // it actually has 4 table columns, but on mobile version, the first column become row - // we need to force 33% width to make each of 3 columns have an equal width of 1/3 screen width - width: calc(100% / 3); - } - } - } } .plans-v2-table-group { @@ -580,6 +534,30 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { font-size: @font-size-small; } } + + tr { + // top right border radius on desktop only + &:first-of-type { + th:last-child > .plans-v2-table-th { + border-top-right-radius: @plans-v2-table-border-radius; + + @media (max-width: @screen-xs-max) { + border-top-right-radius: 0; + } + } + } + + // bottom right border radius on desktop only + &:last-of-type { + td:last-child > .plans-v2-table-cell { + border-bottom-right-radius: @plans-v2-table-border-radius; + + @media (max-width: @screen-xs-max) { + border-bottom-right-radius: 0; + } + } + } + } } .plans-v2-table { @@ -612,7 +590,7 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { background-clip: padding-box; /* needed for firefox when there is bg color */ text-align: center; - &:not(.plans-v2-table-cell-before-green-highlighted-column):not(.plans-v2-table-green-highlighted):not(.plans-v2-table-divider-highlighted):not(.plans-v2-table-discount-highlighted) { + &:not(.plans-v2-table-cell-before-green-highlighted-column):not(.plans-v2-table-green-highlighted):not(.plans-v2-table-divider-highlighted) { border-right: 1px solid @ol-blue-gray-0; @media (max-width: @screen-xs-max) { @@ -693,14 +671,6 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { } } } - - &:last-child td.plans-v2-table-discount-highlighted { - border-bottom: 2px solid @plans-v2-dark-blue; - - @media (max-width: @screen-xs-max) { - border-bottom: unset; - } - } } .fa-check { @@ -734,6 +704,30 @@ span.plans-v2-license-picker-educational-discount-learn-more-container { justify-content: space-around; } + // The forced width below (plans-v2-table-cols-n) is to ensure the table columns have an equal width + // because on mobile, the first column (empty cell on first `tr` and feature name on the rest of `tr`) will be shown as its own row + // and the rest of the `tr` will incorporate a full width of the viewport + tr.plans-v2-table-cols-4:not(.plans-v2-table-divider) { + td, + th:not(:first-of-type) { + width: 25%; + } + } + + tr.plans-v2-table-cols-3:not(.plans-v2-table-divider) { + td, + th:not(:first-of-type) { + width: calc(100% / 3); + } + } + + tr.plans-v2-table-cols-2:not(.plans-v2-table-divider) { + td, + th:not(:first-of-type) { + width: 50%; + } + } + .plans-v2-table-column-header { font-size: 12px; } @@ -1062,7 +1056,7 @@ tr.plans-v2-table-divider { } } - .plans-v2-table-divider-highlighted { + .plans-v2-table-divider-highlighted > div { border-right: none; } } @@ -1114,50 +1108,6 @@ p.plans-v2-table-green-highlighted-text { } } -.plans-v2-table-discount-highlighted { - border-left: 2px solid @plans-v2-dark-blue; - border-right: 2px solid @plans-v2-dark-blue; - - @media (max-width: @screen-xs-max) { - border-left: unset; - border-right: unset; - } -} - -p.plans-v2-table-discount-highlighted-text { - border: 2px solid @plans-v2-dark-blue; - position: absolute; - top: -1 * @plans-v2-highlighted-text-height-desktop; - left: -2px; - display: flex; - justify-content: center; - align-items: center; - // 4px because border width is 2px each side (left and right) - width: calc(100% + 4px); - font-family: @font-family-sans-serif; - font-size: @font-size-small; - line-height: 19px; - font-weight: 700; - background-color: @plans-v2-dark-blue; - border-radius: @plans-v2-table-border-radius @plans-v2-table-border-radius 0 0; - color: @white; - height: @plans-v2-highlighted-text-height-desktop; - margin: 0; - z-index: @plans-v2-discount-highlighted-text-z-index; - - @media (max-width: @screen-sm-max) { - top: -1 * @plans-v2-highlighted-text-height-mobile; - height: @plans-v2-highlighted-text-height-mobile; - } - - @media (max-width: @screen-xs-max) { - padding-left: 5px; - padding-right: 5px; - font-size: @font-size-extra-small; - line-height: 15px; - } -} - .plans-v2-table-sticky-header-container { @media (max-width: @screen-xs-max) { // `height: 60%` is just an arbitrary percentage @@ -1224,10 +1174,6 @@ p.plans-v2-table-discount-highlighted-text { color: @ol-green; } -.plans-v2-table-sticky-header-item-discount-highlighted span { - color: @plans-v2-dark-blue; -} - .plans-v2-faq { // need for specificity to override default a color p > a { diff --git a/services/web/frontend/stylesheets/app/plans.less b/services/web/frontend/stylesheets/app/plans/plans.less similarity index 100% rename from services/web/frontend/stylesheets/app/plans.less rename to services/web/frontend/stylesheets/app/plans/plans.less diff --git a/services/web/frontend/stylesheets/main-style.less b/services/web/frontend/stylesheets/main-style.less index 177aa2025f..15f68041a6 100644 --- a/services/web/frontend/stylesheets/main-style.less +++ b/services/web/frontend/stylesheets/main-style.less @@ -103,8 +103,9 @@ @import 'app/project-list-react.less'; @import 'app/editor.less'; @import 'app/homepage.less'; -@import 'app/plans.less'; -@import 'app/plans-v2.less'; +@import 'app/plans/plans.less'; +@import 'app/plans/plans-ol.less'; +@import 'app/plans/plans-v2.less'; @import 'app/recurly.less'; @import 'app/bonus.less'; @import 'app/register.less'; @@ -139,7 +140,6 @@ @import 'app/blog-posts.less'; @import 'app/cms-page.less'; @import 'app/content_page.less'; -@import 'app/plans-ol.less'; @import 'app/portals.less'; // module styles