Merge pull request #19379 from overleaf/jel-light-touch-separate-rows

[web] Separate column header sections into new rows

GitOrigin-RevId: cffe39933f877eaf07a9e772fd76b8e18dd95d3e
This commit is contained in:
Jessica Lawshe 2024-07-15 08:29:59 -05:00 committed by Copybot
parent fada0b80eb
commit 300e46a28d
2 changed files with 190 additions and 219 deletions

View file

@ -26,6 +26,27 @@ mixin currency_and_payment_methods()
i.fa.fa-cc-paypal.fa-2x(aria-hidden="true")  
span.sr-only #{translate('payment_method_accepted', { paymentMethod: 'Paypal' })}
mixin plans_cta(tableHeadKey, highlighted, eventTrackingKey, additionalEventSegmentation, period)
case tableHeadKey
when 'individual_free'
+btn_buy_individual_free()
when 'individual_collaborator'
+btn_buy_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period)
when 'individual_professional'
+btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period)
when 'group_collaborator'
+btn_buy_group_collaborator(highlighted, eventTrackingKey)
+additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_collaborator')
when 'group_professional'
+btn_buy_group_professional(highlighted, eventTrackingKey)
+additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_professional')
when 'group_organization'
+btn_buy_group_organization(highlighted, eventTrackingKey)
small.plans-table-th-content-additional-link.invisible(aria-hidden="true")
when 'student_free'
+btn_buy_student_free(highlighted)
when 'student_student'
+btn_buy_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period)
mixin plans_table(period, config)
- var maxColumn = config.maxColumn || 4
@ -42,50 +63,116 @@ mixin plans_table(period, config)
- var additionalEventSegmentation = config.additionalEventSegmentation || {}
- var thClass = highlighted ? 'plans-table-green-highlighted' : ''
case tableHeadKey
when 'individual_free'
- var ariaLabel = translate("free")
when 'individual_collaborator'
- var ariaLabel = translate("standard")
when 'individual_professional'
- var ariaLabel = translate("professional")
when 'group_collaborator'
- var ariaLabel = translate("group_standard")
when 'group_professional'
- var ariaLabel = translate("group_professional")
when 'group_organization'
- var ariaLabel = translate("organization")
when 'student_free'
- var ariaLabel = translate("free")
when 'student_student'
- var ariaLabel = translate("student")
default
- var ariaLabel = undefined
th(
aria-label=ariaLabel
class=thClass
scope="col"
)
.plans-table-th
if (highlighted)
p.plans-table-green-highlighted-text #{translate(config.highlightedColumn.text[period]).toUpperCase()}
.plans-table-th-content
if tableHeadKey
case tableHeadKey
when 'individual_free'
| #{translate("free")}
when 'individual_collaborator'
| #{translate("standard")}
when 'individual_professional'
| #{translate("professional")}
when 'group_collaborator'
| #{translate("group_standard")}
when 'group_professional'
| #{translate("group_professional")}
when 'group_organization'
| #{translate("organization")}
when 'student_free'
| #{translate("free")}
when 'student_student'
| #{translate("student")}
tr(class=`plans-table-price-row plans-table-cols-${tableHeadKeys.length}`)
td
- for (const [tableHeadKey] of Object.entries(config.tableHead))
- var highlighted = highlightedColKey === tableHeadKey
- var eventTrackingKey = config.eventTrackingKey
- var additionalEventSegmentation = config.additionalEventSegmentation || {}
- var tdClass = highlighted ? 'plans-table-green-highlighted' : ''
td(class=tdClass)
.plans-table-cell
case tableHeadKey
when 'individual_free'
+table_head_individual_free(highlighted, period)
+table_head_price('free', period)
when 'individual_collaborator'
+table_head_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period)
+table_head_price('collaborator', period)
when 'individual_professional'
+table_head_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period)
+table_head_price('professional', period)
when 'group_collaborator'
+table_head_group_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation)
+table_price_group_collaborator()
when 'group_professional'
+table_head_group_professional(highlighted, eventTrackingKey, additionalEventSegmentation)
+table_price_group_professional()
when 'group_organization'
+table_head_group_organization(highlighted, eventTrackingKey, additionalEventSegmentation)
.plans-table-comments-icon
i.fa.fa-comments-o
when 'student_free'
+table_head_student_free(highlighted, period)
+table_head_price('free', period)
when 'student_student'
+table_head_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period, tableHeadOptions.showExtraContent)
+table_head_price('student', period)
tr(class=`plans-table-cta-mobile plans-table-cols-${tableHeadKeys.length}`)
td
- for (const [tableHeadKey] of Object.entries(config.tableHead))
- var highlighted = highlightedColKey === tableHeadKey
- var eventTrackingKey = config.eventTrackingKey
- var additionalEventSegmentation = config.additionalEventSegmentation || {}
- var tdClass = highlighted ? 'plans-table-green-highlighted' : ''
td(class=tdClass)
.plans-table-cell
.plans-table-btn-buy-container-mobile
+plans_cta(tableHeadKey, highlighted, eventTrackingKey, additionalEventSegmentation, period)
tr(class=`plans-table-short-feature-list plans-table-cols-${tableHeadKeys.length}`)
td
- for (const [tableHeadKey, tableHeadOptions] of Object.entries(config.tableHead))
- var highlighted = highlightedColKey === tableHeadKey
- var eventTrackingKey = config.eventTrackingKey
- var additionalEventSegmentation = config.additionalEventSegmentation || {}
- var tdClass = highlighted ? 'plans-table-green-highlighted' : ''
td(class=tdClass)
.plans-table-cell
div
case tableHeadKey
when 'individual_free'
+table_short_feature_list_free()
when 'individual_collaborator'
+table_short_feature_list_collaborator()
when 'individual_professional'
+table_short_feature_list_professional()
when 'group_collaborator'
+table_short_feature_list_group_collaborator()
when 'group_professional'
+table_short_feature_list_group_professional()
when 'group_organization'
+table_short_feature_list_group_organization(additionalEventSegmentation)
when 'student_free'
+table_short_feature_list_free()
when 'student_student'
+table_short_feature_list_student_student(tableHeadOptions.showExtraContent)
tr(class=`plans-table-cta-desktop plans-table-cols-${tableHeadKeys.length}`)
td
- for (const [tableHeadKey] of Object.entries(config.tableHead))
- var highlighted = highlightedColKey === tableHeadKey
- var eventTrackingKey = config.eventTrackingKey
- var additionalEventSegmentation = config.additionalEventSegmentation || {}
- var tdClass = highlighted ? 'plans-table-green-highlighted' : ''
td(class=tdClass)
.plans-table-cell
.plans-table-btn-buy-container-desktop
+plans_cta(tableHeadKey, highlighted, eventTrackingKey, additionalEventSegmentation, period)
for featuresPerSection in config.features
- var dividerColspan = Object.values(config.tableHead).length + 1
@ -115,7 +202,7 @@ mixin plans_table(period, config)
span.sr-only #{translate(featuresPerSection.dividerInfo)}
for feature, featureIndex in featuresPerSection.items
tr(
class=`plans-table-cols-${tableHeadKeys.length}`
class=`plans-table-feature-row plans-table-cols-${tableHeadKeys.length}`
)
th(
event-tracking="plans-page-table"
@ -123,6 +210,7 @@ mixin plans_table(period, config)
event-tracking-ga="subscription-funnel"
event-tracking-label=`${feature.feature}`
scope="row"
class=`${featureIndex === 0 ? 'plans-table-first-feature-header' : ''}`
)
.plans-table-feature-name
if feature.info
@ -170,16 +258,6 @@ mixin table_short_feature_list_free()
ul.plans-table-th-content-benefit
li #{translate("one_collaborator")}
mixin table_head_individual_free(highlighted, period)
.plans-table-th-content
p.plans-table-th-content-title #{translate("free")}
+table_head_price('free', period)
.plans-table-btn-buy-container-mobile
+btn_buy_individual_free()
+table_short_feature_list_free()
.plans-table-btn-buy-container-desktop
+btn_buy_individual_free()
//- individual plan mixins
mixin table_short_feature_list_collaborator()
@ -187,16 +265,6 @@ mixin table_short_feature_list_collaborator()
li !{translate("x_collaborators_per_project", {collaboratorsCount: '10'})}
li #{translate("all_premium_features")}
mixin table_head_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period)
.plans-table-th-content
p.plans-table-th-content-title #{translate("standard")}
+table_head_price('collaborator', period)
.plans-table-btn-buy-container-mobile
+btn_buy_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period)
+table_short_feature_list_collaborator()
.plans-table-btn-buy-container-desktop
+btn_buy_individual_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation, period)
//- professional plan mixins
mixin table_short_feature_list_professional()
@ -204,16 +272,6 @@ mixin table_short_feature_list_professional()
li !{translate("unlimited_collabs_rt",{},["b"])}
li #{translate("all_premium_features")}
mixin table_head_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period)
.plans-table-th-content
p.plans-table-th-content-title #{translate("professional")}
+table_head_price('professional', period)
.plans-table-btn-buy-container-mobile
+btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period)
+table_short_feature_list_professional()
.plans-table-btn-buy-container-desktop
+btn_buy_individual_professional(highlighted, eventTrackingKey, additionalEventSegmentation, period)
//- group_collaborator plan mixins
mixin table_short_feature_list_group_collaborator()
@ -223,26 +281,14 @@ mixin table_short_feature_list_group_collaborator()
+table_head_group_total_per_year('collaborator')
mixin table_price_group_collaborator()
.plans-v2-table-price-container
strike.plans-v2-table-price-before-discount
.plans-table-price-container
s
+gen_localized_price_for_plan_view('collaborator', 'annual')
p.plans-v2-table-price
span(data-ol-plans-v2-group-price-per-user='collaborator') #{initialLocalizedGroupPrice.pricePerUser.collaborator}
p.plans-v2-table-price-period-label
| #{translate('per_user_year')}
mixin table_head_group_collaborator(highlighted, eventTrackingKey, additionalEventSegmentation)
.plans-table-th-content
p.plans-table-th-content-title #{translate("group_standard")}
+table_price_group_collaborator()
.plans-table-btn-buy-container-mobile
+btn_buy_group_collaborator(highlighted, eventTrackingKey)
+additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_collaborator')
+table_short_feature_list_group_collaborator()
.plans-table-btn-buy-container-desktop
+btn_buy_group_collaborator(highlighted, eventTrackingKey)
+additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_collaborator')
//- group_professional plan mixins
mixin table_short_feature_list_group_professional()
@ -252,26 +298,14 @@ mixin table_short_feature_list_group_professional()
+table_head_group_total_per_year('professional')
mixin table_price_group_professional()
.plans-v2-table-price-container
strike.plans-v2-table-price-before-discount
.plans-table-price-container
s
+gen_localized_price_for_plan_view('professional', 'annual')
p.plans-v2-table-price
span(data-ol-plans-v2-group-price-per-user='professional') #{initialLocalizedGroupPrice.pricePerUser.professional}
p.plans-v2-table-price-period-label
| #{translate('per_user_year')}
mixin table_head_group_professional(highlighted, eventTrackingKey, additionalEventSegmentation)
.plans-table-th-content
p.plans-table-th-content-title #{translate("group_professional")}
+table_price_group_professional()
.plans-table-btn-buy-container-mobile
+btn_buy_group_professional(highlighted, eventTrackingKey)
+additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_professional')
+table_short_feature_list_group_professional()
.plans-table-btn-buy-container-desktop
+btn_buy_group_professional(highlighted, eventTrackingKey)
+additional_link_group(eventTrackingKey, additionalEventSegmentation, 'group_professional')
//- group mixins
mixin table_head_group_total_per_year(groupPlan)
@ -299,20 +333,6 @@ mixin table_short_feature_list_group_organization(additionalEventSegmentation)
event-segmentation=segmentation
) #{translate("also_available_as_on_premises")}
mixin table_head_group_organization(highlighted, eventTrackingKey, additionalEventSegmentation)
.plans-table-th-content
p.plans-table-th-content-title #{translate("organization")}
.plans-table-comments-icon
i.fa.fa-comments-o
.plans-table-btn-buy-container-mobile
+btn_buy_group_organization(highlighted, eventTrackingKey)
small.plans-table-th-content-additional-link.invisible(aria-hidden="true")
+table_short_feature_list_group_organization(additionalEventSegmentation)
.plans-table-btn-buy-container-desktop
+btn_buy_group_organization(highlighted, eventTrackingKey)
small.plans-table-th-content-additional-link.invisible(aria-hidden="true")
mixin group_plans_license_picker()
form.plans-license-picker-form(data-ol-plans-v2-license-picker-form)
.plans-v2-license-picker-select-container
@ -364,18 +384,6 @@ mixin group_plans_license_picker()
span )
span.sr-only #{translate("apply_educational_discount_info")}
//- student free plan mixins
mixin table_head_student_free(highlighted, period)
div.plans-table-th-content
p.plans-table-th-content-title #{translate("free")}
+table_head_price('free', period)
.plans-table-btn-buy-container-mobile
+btn_buy_student_free(highlighted)
+table_short_feature_list_free()
.plans-table-btn-buy-container-desktop
+btn_buy_student_free(highlighted)
//- student plan mixins
mixin table_short_feature_list_student_student(showExtraContent)
@ -386,23 +394,12 @@ mixin table_short_feature_list_student_student(showExtraContent)
li
b !{translate("for_students_only")}
mixin table_head_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period, showExtraContent)
div.plans-table-th-content
p.plans-table-th-content-title #{translate("student")}
+table_head_price('student', period)
.plans-table-btn-buy-container-mobile
+btn_buy_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period)
+table_short_feature_list_student_student(showExtraContent)
.plans-table-btn-buy-container-desktop
+btn_buy_student_student(highlighted, eventTrackingKey, additionalEventSegmentation, period)
//- all plans mixins
mixin table_head_price(plan, period)
div.plans-v2-table-price-container
div.plans-table-price-container
if plan !== 'free' && period === 'annual'
strike.plans-v2-table-price-before-discount
s
+gen_localized_price_for_plan_view(plan, 'monthlyTimesTwelve')
p.plans-v2-table-price
+gen_localized_price_for_plan_view(plan, period)

View file

@ -442,10 +442,6 @@
@media (max-width: @screen-xs-max) {
margin-top: 60px + @plans-highlighted-text-height-desktop;
th .plans-table-th-content {
min-height: 280px;
}
}
}
@ -464,24 +460,6 @@
.plans-table-group {
margin-top: 26px + @plans-highlighted-text-height-desktop;
p.plans-table-th-content-title {
// Reduce font size of table heading for screen size >= @screen-lg (1200px) from 20px to 19px
// In the English version of overleaf, 20px is enough for the text to not be wrapped to the next line, the longest text is the 2nd column of group tab: "Group Professional".
// In the English version, "Group Professional" won't be wrapped to two separate lines with 20px font size for big screen.
// In other languages, for example, German (subdomain `de`), 20px is too big so the text is wrapped and breaks the UI. 19px is enough to fit the text on one line on the German site.
// This font-size reduction is a case-to-case basis since we don't have any way to know the max length of every language unless we've translated them all.
// There's probably a smarter way to do it, but probably also more complex. This change in font should be acceptable and we can revisit it every time there's a longer text.
font-size: 19px;
@media (max-width: @screen-md-max) {
font-size: @font-size-base;
}
@media (max-width: @screen-xs-max) {
font-size: @font-size-small;
}
}
}
.plans-table {
@ -545,6 +523,35 @@
}
}
.plans-table-cta-desktop,
.plans-table-cta-mobile,
.plans-table-short-feature-list,
.plans-table-price-row {
td > div {
border-top: 0;
}
}
th[scope='col'] > div {
padding: var(--spacing-06) var(--spacing-08);
}
th[scope='row'] > div {
padding: var(--spacing-05) var(--spacing-08) var(--spacing-05)
var(--spacing-05);
}
td > div > div {
// apply spacing to inner div to not interfere with border
padding: var(--spacing-05) var(--spacing-08);
@media (max-width: @screen-xs-max) {
padding: var(--spacing-05);
}
}
tr.plans-table-divider > td > div {
// td style above not applied since there is only 1 level of div within divider cells
padding: var(--spacing-05) var(--spacing-08);
}
// We want these `div` inside `th` and `td` to have a 100% height since
// white backgrounds are defined here:
// 1. `td > div.plans-table-cell`
@ -622,12 +629,11 @@
}
th[scope='col'] {
font-family: @headings-font-family;
font-size: @font-size-h2;
font-weight: @headings-font-weight;
line-height: @headings-line-height;
font-family: 'Noto Sans', sans-serif;
font-size: var(--font-size-05);
font-weight: 600;
line-height: var(--line-height-04);
vertical-align: top;
padding: 0;
position: relative;
&.plans-table-green-highlighted {
@ -648,15 +654,12 @@
position: relative;
}
// css hack for table border-radius on the first feature name
&:nth-child(2) {
th[scope='row']:first-child {
.plans-table-feature-name {
border-top-left-radius: @plans-table-border-radius;
.plans-table-first-feature-header {
.plans-table-feature-name {
border-top-left-radius: @plans-table-border-radius;
@media (max-width: @screen-xs-max) {
border-top-left-radius: 0;
}
@media (max-width: @screen-xs-max) {
border-top-left-radius: 0;
}
}
}
@ -673,7 +676,6 @@
// direct child selector to NOT affect the generated tooltip
td > div {
text-align: center;
padding: 6px;
.plans-table-divider-label {
margin-bottom: 0;
@ -702,8 +704,6 @@
td > div {
background-color: var(--neutral-20);
border: 0;
padding: 15px 5px;
i {
display: none;
}
@ -758,7 +758,7 @@
@media (min-width: @screen-sm-min) {
// highlight rows on hover
tr:not(.plans-table-divider):not(:first-child):hover {
.plans-table-feature-row:hover {
.plans-table-feature-name,
.plans-table-cell {
background-color: @table-hover-bg;
@ -802,9 +802,15 @@
font-size: 12px;
}
// hide the first column header
tr:first-child th:first-child {
display: none;
// hide the first cell (which has no content)
tr:first-child,
.plans-table-price-row,
.plans-table-cta-mobile,
.plans-table-short-feature-list {
th:first-child,
td:first-child {
display: none;
}
}
// for mobile, we need to show the feature name (the first td) as its own row
@ -840,7 +846,6 @@
@media (max-width: @screen-xs-max) {
.plans-table-cell-content {
padding: 6px;
min-height: @plans-table-td-mobile-min-height;
}
}
@ -852,13 +857,7 @@
.plans-table-th-content {
display: flex;
flex-direction: column;
min-height: 321px;
height: 100%;
padding: 10px 13px;
@media (max-width: @screen-md-max) {
min-height: 330px;
}
@media (max-width: @screen-sm-max) {
padding-left: @padding-xs;
@ -912,30 +911,6 @@
}
}
p.plans-table-th-content-title {
font-size: @font-size-large;
padding-bottom: @padding-sm;
border-bottom: 1px solid @gray-lighter;
margin-bottom: @margin-lg;
@media (max-width: @screen-md-max) {
font-size: @font-size-base;
}
// `plans-table-th-content-title` is visually invisible on screen size less than @screen-xs-max
// because there is a sticky header (`plans-v2-table-sticky-header` class) that "replace" the content visually
// (see the `@plans-table-sticky-header-z-index` variable that make the sticky header element is "above" the whole table)
// however, we still need to properly styling the `plans-table-th-content-title` for small screen size to
// fit this element to the size of the sticky header
// this trick is used because th element can not have a `position: sticky` rule, at least for our use case
@media (max-width: @screen-xs-max) {
min-height: 40px;
margin-bottom: @margin-md;
font-size: @font-size-small;
padding-bottom: 0;
}
}
p.plans-table-th-content-benefit,
ul.plans-table-th-content-benefit {
padding-top: 15px;
@ -961,8 +936,25 @@
font-weight: 700;
}
.plans-v2-table-price-container {
.plans-table-price-container {
position: relative;
s {
position: absolute;
left: 0;
top: -27px;
font-weight: 700;
font-size: @font-size-small;
line-height: 42px;
display: flex;
justify-content: center;
width: 100%;
color: @ol-blue-gray-2;
@media (max-width: @screen-xs-max) {
font-size: @font-size-extra-small;
}
}
}
p.plans-v2-table-price-period-label {
@ -987,22 +979,6 @@
}
}
strike.plans-v2-table-price-before-discount {
position: absolute;
top: -27px;
font-weight: 700;
font-size: @font-size-small;
line-height: 42px;
display: flex;
justify-content: center;
width: 100%;
color: @ol-blue-gray-2;
@media (max-width: @screen-xs-max) {
font-size: @font-size-extra-small;
}
}
small.plans-table-th-content-additional-link {
text-transform: lowercase;
margin-top: @margin-xs;
@ -1020,7 +996,6 @@
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 6px 6px 18px;
i.plans-table-feature-question-icon {
margin-left: 10px;
@ -1033,7 +1008,6 @@
@media (max-width: @screen-xs-max) {
display: inline-block;
text-align: left;
padding: 6px;
width: 100%;
background-color: @ol-blue-gray-0;
min-height: @plans-table-td-mobile-min-height;
@ -1140,7 +1114,7 @@
flex: 1 1 0px;
span {
margin: 0px @margin-xs;
margin: @margin-xs;
border-bottom: 1px solid #cccccc;
height: 100%;
display: flex;