From e8bae62f04063fe6d70fe242883bbdf719522311 Mon Sep 17 00:00:00 2001 From: Harry Rein Date: Tue, 25 Jul 2017 15:30:42 -0400 Subject: [PATCH] UX improvements on learner profile. LEARNER-1857 This story constitutes a large change to the UX of the learner profile. Some specific changes include adding a flexible learner profile card, limiting the bio entry to only 300 characters and assuring that the page is responsive. --- .../acceptance/pages/lms/learner_profile.py | 16 -- .../tests/lms/test_learner_profile.py | 4 - lms/static/js/views/fields.js | 28 ++- lms/static/sass/_build-lms-v1.scss | 2 +- lms/static/sass/elements/_pagination.scss | 2 +- .../{views => features}/_learner-profile.scss | 197 +++++++++++++----- lms/static/sass/partials/base/_variables.scss | 6 + lms/static/sass/shared/_fields.scss | 4 +- lms/static/sass/shared/_header.scss | 2 +- .../fields/field_dropdown.underscore | 24 +-- .../fields/field_dropdown_account.underscore | 18 +- .../fields/field_readonly.underscore | 3 +- .../fields/field_textarea.underscore | 19 +- .../views/course_home_messages.py | 7 +- .../js/learner_profile_factory.js | 29 ++- .../spec/views/learner_profile_view_spec.js | 14 +- .../js/spec/views/section_two_tab_spec.js | 2 +- .../js/spec_helpers/helpers.js | 9 +- .../js/views/learner_profile_view.js | 22 +- .../templates/learner_profile.underscore | 22 +- .../templates/section_two.underscore | 4 +- 21 files changed, 292 insertions(+), 142 deletions(-) rename lms/static/sass/{views => features}/_learner-profile.scss (73%) diff --git a/common/test/acceptance/pages/lms/learner_profile.py b/common/test/acceptance/pages/lms/learner_profile.py index 73751e0f30..91d1d6e255 100644 --- a/common/test/acceptance/pages/lms/learner_profile.py +++ b/common/test/acceptance/pages/lms/learner_profile.py @@ -13,10 +13,6 @@ from common.test.acceptance.tests.helpers import select_option_by_value PROFILE_VISIBILITY_SELECTOR = '#u-field-select-account_privacy option[value="{}"]' PROFILE_VISIBILITY_INPUT = '#u-field-select-account_privacy' -FIELD_ICONS = { - 'country': 'fa-map-marker', - 'language_proficiencies': 'fa-comment', -} class Badge(PageObject): @@ -214,18 +210,6 @@ class LearnerProfilePage(FieldsMixin, PageObject): self.wait_for_ajax() return self.q(css='#u-field-select-account_privacy').visible - def field_icon_present(self, field_id): - """ - Check if an icon is present for a field. Only dropdown fields have icons. - - Arguments: - field_id (str): field id - - Returns: - True/False - """ - return self.icon_for_field(field_id, FIELD_ICONS[field_id]) - def wait_for_public_fields(self): """ Wait for `country`, `language` and `bio` fields to be visible. diff --git a/common/test/acceptance/tests/lms/test_learner_profile.py b/common/test/acceptance/tests/lms/test_learner_profile.py index 95ef7d452b..f896cea2bb 100644 --- a/common/test/acceptance/tests/lms/test_learner_profile.py +++ b/common/test/acceptance/tests/lms/test_learner_profile.py @@ -367,8 +367,6 @@ class OwnLearnerProfilePageTest(LearnerProfileTestMixin, AcceptanceTest): profile_page.make_field_editable('country') self.assertEqual(profile_page.mode_for_field('country'), 'edit') - self.assertTrue(profile_page.field_icon_present('country')) - def test_language_field(self): """ Test behaviour of `Language` field. @@ -396,8 +394,6 @@ class OwnLearnerProfilePageTest(LearnerProfileTestMixin, AcceptanceTest): profile_page.make_field_editable('language_proficiencies') self.assertTrue(profile_page.mode_for_field('language_proficiencies'), 'edit') - self.assertTrue(profile_page.field_icon_present('language_proficiencies')) - def test_about_me_field(self): """ Test behaviour of `About Me` field. diff --git a/lms/static/js/views/fields.js b/lms/static/js/views/fields.js index 6f87581da3..878333df28 100644 --- a/lms/static/js/views/fields.js +++ b/lms/static/js/views/fields.js @@ -515,15 +515,16 @@ 'click .wrapper-u-field': 'startEditing', 'click .u-field-placeholder': 'startEditing', 'focusout textarea': 'finishEditing', - 'change textarea': 'adjustTextareaHeight', - 'keyup textarea': 'adjustTextareaHeight', + 'change textarea': 'manageTextareaContentChange', + 'keyup textarea': 'manageTextareaContentChange', 'keydown textarea': 'onKeyDown', - 'paste textarea': 'adjustTextareaHeight', - 'cut textarea': 'adjustTextareaHeight' + 'paste textarea': 'manageTextareaContentChange', + 'cut textarea': 'manageTextareaContentChange' }, initialize: function(options) { - _.bindAll(this, 'render', 'onKeyDown', 'adjustTextareaHeight', 'fieldValue', 'saveValue', 'updateView'); + _.bindAll(this, 'render', 'onKeyDown', 'adjustTextareaHeight', 'manageTextareaContentChange', + 'fieldValue', 'saveValue', 'updateView'); this._super(options); this.listenTo(this.model, 'change:' + this.options.valueAttribute, this.updateView); }, @@ -541,7 +542,8 @@ value: value, message: this.helpMessage, messagePosition: this.options.messagePosition || 'footer', - placeholderValue: this.options.placeholderValue + placeholderValue: this.options.placeholderValue, + maxCharacters: this.options.maxCharacters || '' })); this.delegateEvents(); this.title((this.modelValue() || this.mode === 'edit') ? @@ -562,12 +564,26 @@ } }, + updateCharCount: function() { + var curCharCount; + // Update character count for textarea + if (this.options.maxCharacters) { + curCharCount = $('#u-field-textarea-' + this.options.valueAttribute).val().length; + $('.u-field-footer .current-char-count').text(curCharCount); + } + }, + adjustTextareaHeight: function() { if (this.persistChanges === false) { return; } var textarea = this.$('textarea'); textarea.css('height', 'auto').css('height', textarea.prop('scrollHeight') + 10); }, + manageTextareaContentChange: function() { + this.updateCharCount(); + this.adjustTextareaHeight(); + }, + modelValue: function() { var value = this._super(); return value ? $.trim(value) : ''; diff --git a/lms/static/sass/_build-lms-v1.scss b/lms/static/sass/_build-lms-v1.scss index ddca292653..3a311a74e6 100644 --- a/lms/static/sass/_build-lms-v1.scss +++ b/lms/static/sass/_build-lms-v1.scss @@ -55,7 +55,6 @@ // base - specific views @import "views/account-settings"; -@import "views/learner-profile"; @import 'views/login-register'; @import 'views/verification'; @import 'views/decoupled-verification'; @@ -69,6 +68,7 @@ // features @import 'features/bookmarks-v1'; +@import 'features/learner-profile'; // search @import 'search/search'; diff --git a/lms/static/sass/elements/_pagination.scss b/lms/static/sass/elements/_pagination.scss index 21d3fea81f..fa907f93ea 100644 --- a/lms/static/sass/elements/_pagination.scss +++ b/lms/static/sass/elements/_pagination.scss @@ -74,7 +74,7 @@ margin: 0 ($baseline*0.75); padding: ($baseline/4); text-align: center; - color: $gray; + color: $gray-d1; } .current-page { diff --git a/lms/static/sass/views/_learner-profile.scss b/lms/static/sass/features/_learner-profile.scss similarity index 73% rename from lms/static/sass/views/_learner-profile.scss rename to lms/static/sass/features/_learner-profile.scss index 99ff1d9248..8a0226c168 100644 --- a/lms/static/sass/views/_learner-profile.scss +++ b/lms/static/sass/features/_learner-profile.scss @@ -25,8 +25,6 @@ } .profile-image-field { - @include float(left); - button { background: transparent !important; border: none !important; @@ -41,13 +39,18 @@ .image-wrapper { width: $profile-image-dimension; position: relative; + margin: auto; .image-frame { display: block; position: relative; width: $profile-image-dimension; height: $profile-image-dimension; - border-radius: ($baseline/4); + border-radius: ($profile-image-dimension/2); + overflow: hidden; + border: 3px solid $gray-lightest; + margin-top: $baseline*-0.75; + background: $white; } .u-field-upload-button { @@ -55,13 +58,12 @@ top: 0; width: $profile-image-dimension; height: $profile-image-dimension; - border-radius: ($baseline/4); + border-radius: ($profile-image-dimension/2); border: 2px dashed transparent; background: rgba(229,241,247, .8); color: $link-color; text-shadow: none; @include transition(all $tmg-f1 ease-in-out 0s); - opacity: 0; z-index: 6; i { @@ -87,17 +89,20 @@ line-height: 1.3em; text-align: center; z-index: 7; + color: $base-font-color; } .upload-button-input { position: absolute; - top: -($profile-image-dimension * 2); + top: 0; @include left(0); width: $profile-image-dimension; + border-radius: ($profile-image-dimension/2); height: 100%; cursor: pointer; z-index: 5; outline: 0; + opacity: 0; } .u-field-remove-button { @@ -113,6 +118,7 @@ .wrapper-profile { min-height: 200px; + background-color: $gray-lightest; .ui-loading-indicator { margin-top: 100px; @@ -133,7 +139,7 @@ @extend .container; border: none; box-shadow: none; - padding: 0 ($baseline*1.5); + padding: 0 ($baseline*3); } .u-field-title { @@ -164,53 +170,93 @@ .wrapper-profile-sections { @extend .container; - padding: 0 ($baseline*1.5); + @include padding($baseline*1.5, $baseline*1.5, $baseline*1.5, 0); + min-width: 0; + + @media (max-width: $learner-profile-container-flex) { // Switch to map-get($grid-breakpoints,md) for bootstrap + @include margin-left(0); + @include padding($baseline*1.5, 0, $baseline*1.5, 0); + } + } + + .profile-header { + @include padding(0, $baseline*2, $baseline, $baseline*3); + + .header { + @extend %t-title4; + @extend %t-ultrastrong; + display: inline-block; + } + + .subheader { + @extend %t-title6; + } } .wrapper-profile-section-one { - width: 100%; - display: inline-block; - margin-top: ($baseline*1.5); - @include margin-left($baseline/2); + @include float(left); + @include margin-left($baseline*3); + width: 300px; + background-color: $white; + border-top: 5px solid $blue; + padding-bottom: $baseline; + + @media (max-width: $learner-profile-container-flex) { // Switch to map-get($grid-breakpoints,md) for bootstrap + @include margin-left(0); + width: 100%; + } } .profile-section-one-fields { - @include float(left); - width: flex-grid(4, 12); - @include margin-left($baseline); + margin: 0 $baseline/2; .u-field { - margin-bottom: ($baseline/4); - padding-top: 3px; - padding-bottom: 3px; - @include padding-left(3px); - } - - .u-field-username { - - input[type="text"] { - font-weight: 600; - } + @extend %t-weight4; + @include padding(0, 0, 0, 3px); + color: $base-font-color; .u-field-value { - width: 350px; - @extend %t-title4; + @extend %t-weight4; + width: calc(100% - 40px); + + .u-field-value-readonly { + @extend %t-weight3; + } + } + + .u-field-title { + color: $base-font-color; + font-size: $body-font-size; + display: block; + } + + &.u-field-dropdown { + margin-top: $baseline/5; + + &:not(.editable-never) { + cursor: pointer; + } + + &:not(:last-child) { + padding-bottom: $baseline/4; + border-bottom: 1px solid $gray-lighter; + } } } - .u-field-icon { - display: inline-block; - vertical-align: baseline; - } + &>.u-field { + &:not(:first-child) { + font-size: $body-font-size; + color: $base-font-color; + font-weight: $font-light; + margin-bottom: 0; + } - .u-field-title { - width: 0; - } - - .u-field-value { - width: 200px; - display: inline-block; - vertical-align: baseline; + &:first-child { + @extend %t-title4; + @extend %t-weight4; + font-size: em(24); + } } select { @@ -230,16 +276,29 @@ } } - .wrapper-profile-section-two { - padding-top: 1em; - width: flex-grid(8, 12); - } + .wrapper-profile-section-container-two { + @include float(left); + width: calc(100% - 380px); + max-width: $learner-profile-container-flex; // Switch to map-get($grid-breakpoints,md) for bootstrap - .profile-section-two-fields { + @media (max-width: $learner-profile-container-flex) { // Switch to map-get($grid-breakpoints,md) for bootstrap + width: 100%; + margin-top: $baseline; + } .u-field-textarea { margin-bottom: ($baseline/2); - padding: ($baseline/2) ($baseline*.75) ($baseline*.75) ($baseline*.75); + padding: 0 ($baseline*.75) ($baseline*.75) ($baseline*.75); + + .u-field-header { + position: relative; + + .u-field-message { + @include right(0); + top: $baseline/4; + position: absolute; + } + } &.editable-toggle { cursor: pointer; @@ -247,22 +306,30 @@ } .u-field-title { - @extend %t-title5; - @extend %t-weight4; + @extend %t-title6; + @extend %t-weight5; display: inline-block; margin-top: 0; margin-bottom: ($baseline/4); - color: inherit; + color: $gray-dark; + width: 100%; } .u-field-value { @extend %t-copy-base; width: 100%; + overflow: scroll; textarea { width: 100%; background-color: transparent; + border-radius: 5px; + border-color: $gray-d1; + resize: none; white-space: pre-line; + outline: 0; + box-shadow: none; + -webkit-appearance: none; } a { @@ -273,16 +340,22 @@ .u-field-message { @include float(right); width: auto; + + .message-can-edit { + position: absolute; + } } .u-field.mode-placeholder { padding: $baseline; + margin: $baseline * 0.75; border: 2px dashed $gray-l3; + i { font-size: 12px; @include padding-right(5px); vertical-align: middle; - color: $gray; + color: $base-font-color; } .u-field-title { width: 100%; @@ -293,7 +366,7 @@ text-align: center; line-height: 1.5em; @extend %t-copy-sub1; - color: $gray; + color: $base-font-color; } } @@ -304,6 +377,28 @@ color: $link-color; } } + + .wrapper-u-field { + font-size: $body-font-size; + color: $base-font-color; + + .u-field-header .u-field-title{ + color: $base-font-color; + } + + .u-field-footer { + .field-textarea-character-count { + @extend %t-weight1; + @include float(right); + margin-top: $baseline/4; + } + } + } + + .profile-private-message { + @include padding-left($baseline*0.75); + line-height: 3.0em; + } } .badge-paging-header { diff --git a/lms/static/sass/partials/base/_variables.scss b/lms/static/sass/partials/base/_variables.scss index 6ff97cec34..f15a9c7929 100644 --- a/lms/static/sass/partials/base/_variables.scss +++ b/lms/static/sass/partials/base/_variables.scss @@ -223,6 +223,9 @@ $success-color-hover: rgb(0, 129, 0) !default; // ---------------------------- // #COLORS- Bootstrap-style // ---------------------------- +$gray-dark: #4e5455 !default; +$gray-lighter: #eceeef !default; +$gray-lightest: #f7f7f9 !default; $state-success-text: $black !default; $state-success-bg: #dff0d8 !default; @@ -545,6 +548,9 @@ $palette-success-border: #b9edb9; $palette-success-back: #ecfaec; $palette-success-text: #008100; +// learner profile elements +$learner-profile-container-flex: 768px; + // course elements $content-wrapper-bg: $white !default; $course-bg-color: $uxpl-grayscale-x-back !default; diff --git a/lms/static/sass/shared/_fields.scss b/lms/static/sass/shared/_fields.scss index 02e51ac95c..e2d3e8a022 100644 --- a/lms/static/sass/shared/_fields.scss +++ b/lms/static/sass/shared/_fields.scss @@ -12,7 +12,7 @@ border-radius: 3px; span { - color: $gray; + color: $gray-d1; } &:hover { @@ -84,7 +84,7 @@ .u-field-title { width: flex-grid(3, 12); display: inline-block; - color: $gray; + color: $gray-d1; vertical-align: top; margin-bottom: 0; -webkit-font-smoothing: antialiased; diff --git a/lms/static/sass/shared/_header.scss b/lms/static/sass/shared/_header.scss index 1e47a40a22..6eabedef18 100644 --- a/lms/static/sass/shared/_header.scss +++ b/lms/static/sass/shared/_header.scss @@ -3,7 +3,7 @@ .header-global { @extend %ui-depth1; - border-bottom: 2px solid $header-border-color; + border-bottom: 1px solid $header-border-color; box-shadow: 0 1px 5px 0 $shadow-l1; background: $header-bg; position: relative; diff --git a/lms/templates/fields/field_dropdown.underscore b/lms/templates/fields/field_dropdown.underscore index 097365c9dc..48826683a1 100644 --- a/lms/templates/fields/field_dropdown.underscore +++ b/lms/templates/fields/field_dropdown.underscore @@ -1,17 +1,17 @@ -<% if (editable !== 'never') { %> - <% if (title && titleVisible) { %> - - <% } else { %> - - <% } %> +<% if (title && titleVisible) { %> + +<% } else { %> + <% } %> -<% if (iconName) { %> - +<% if (editable !== 'never') { %> + <% if (iconName) { %> + + <% } %> <% } %> diff --git a/lms/templates/fields/field_dropdown_account.underscore b/lms/templates/fields/field_dropdown_account.underscore index 6bb8bef0ad..4fa6e5e458 100644 --- a/lms/templates/fields/field_dropdown_account.underscore +++ b/lms/templates/fields/field_dropdown_account.underscore @@ -1,14 +1,12 @@
- <% if (editable !== 'never') { %> - <% if (title && titleVisible) { %> - - <% } else { %> - - <% } %> + <% if (title && titleVisible) { %> + + <% } else { %> + <% } %> <% if (iconName) { %> diff --git a/lms/templates/fields/field_readonly.underscore b/lms/templates/fields/field_readonly.underscore index 307b014b64..96293ff01b 100644 --- a/lms/templates/fields/field_readonly.underscore +++ b/lms/templates/fields/field_readonly.underscore @@ -1,6 +1,7 @@ <% if (title) { %> - + <% } %> + <%- screenReaderTitle %> <%- value %> diff --git a/lms/templates/fields/field_textarea.underscore b/lms/templates/fields/field_textarea.underscore index 79a959b644..915f4f4553 100644 --- a/lms/templates/fields/field_textarea.underscore +++ b/lms/templates/fields/field_textarea.underscore @@ -1,4 +1,4 @@ -
+
<% if (mode === 'edit') { %> @@ -15,7 +15,7 @@
- aria-labelledby="u-field-title-<%- id %>">