From 49d5175ce2367cd08522226e3010bc2342274760 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Wed, 13 Dec 2023 13:10:38 -0700 Subject: [PATCH 1/6] Change profile layout to more closely match other pages Changelog: changed --- .../stylesheets/page_bundles/profile.scss | 13 +- app/views/users/show.html.haml | 173 +++++++++--------- locale/gitlab.pot | 3 - spec/features/users/show_spec.rb | 10 +- 4 files changed, 98 insertions(+), 101 deletions(-) diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss index cc75a4ad8fc9f1..1fbd0a7f2a5e55 100644 --- a/app/assets/stylesheets/page_bundles/profile.scss +++ b/app/assets/stylesheets/page_bundles/profile.scss @@ -56,8 +56,8 @@ .user-profile-image { .gl-avatar { @include media-breakpoint-up(md) { - height: 7.5rem; - width: 7.5rem; + height: 6.5rem; + width: 6.5rem; } } } @@ -235,11 +235,18 @@ @include media-breakpoint-up(lg) { display: grid; - grid-template-columns: minmax(240px, 1fr) 3fr; + grid-template-columns: 3fr minmax(240px, 1fr); gap: 3rem; } } +.user-profile-header > :first-child{ + order: 2; + @include media-breakpoint-up(md) { + order: initial; + } +} + .user-profile-sidebar { z-index: 2; } diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index e6fd5618582c71..39734b11f5e799 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -13,31 +13,99 @@ = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") %div{ class: container_class } + .user-profile-header.gl-display-flex.gl-justify-content-space-between.gl-flex-direction-column.gl-md-flex-direction-row.gl-mt-5 + .gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row.gl-md-align-items-center.gl-column-gap-5 + = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', alt: 'View large avatar' do + = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" }) + %div + %h1.gl-font-size-h1.gl-line-height-1.gl-mb-1.gl-mt-0{ itemprop: 'name' } + = user_display_name(@user) + %h2.gl-font-size-h2.gl-text-gray-600.gl-font-weight-normal.gl-my-0 + = @user.to_reference + - if !@user.blocked? && @user.confirmed? + - if @user.pronouns.present? || @user.pronunciation.present? + .gl-font-sm.gl-mt-3 + - if @user.pronunciation.present? + %p.gl-mb-0 + = s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation } + - if @user.pronouns.present? + %p.gl-mb-0 + = s_("UserProfile|Pronouns: %{pronouns}") % { pronouns: @user.pronouns } + %div + .cover-controls.gl-display-flex.gl-gap-3.gl-mb-4.gl-md-justify-content-end + = render 'users/follow_user' + -# The following edit button is mutually exclusive to the follow user button, they won't be shown together + - if @user == current_user + = render Pajamas::ButtonComponent.new(href: profile_path, + button_options: { title: s_('UserProfile|Edit profile') }) do + = s_("UserProfile|Edit profile") + = render 'users/view_gpg_keys' + = render 'users/view_user_in_admin_area' + .js-user-profile-actions{ data: user_profile_actions_data(@user) } .user-profile - .user-profile-sidebar - .profile-header.gl-py-6.gl-overflow-y-auto.gl-sm-pr-4 + .user-profile-content.gl-pt-5 + - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user) + #js-profile-tabs{ data: user_profile_tabs_app_data(@user) } + - unless Feature.enabled?(:profile_tabs_vue, current_user) + .tab-content.gl-overflow-hidden + - if profile_tab?(:overview) + #js-overview.tab-pane + = render "users/overview" - = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', alt: 'View large avatar' do - = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" }) + - if profile_tab?(:activity) + #activity.tab-pane + .flash-container + - if can?(current_user, :read_cross_project) + .content_list.user-activity-content{ data: { href: user_activity_path } } + .loading + = gl_loading_icon(size: 'md') + - unless @user.bot? + - if profile_tab?(:groups) + #groups.tab-pane + -# This tab is always loaded via AJAX + + - if profile_tab?(:contributed) + #contributed.tab-pane + -# This tab is always loaded via AJAX + - if profile_tab?(:projects) + #projects.tab-pane + -# This tab is always loaded via AJAX + + - if profile_tab?(:starred) + #starred.tab-pane + -# This tab is always loaded via AJAX + + - if profile_tab?(:snippets) + #snippets.tab-pane + -# This tab is always loaded via AJAX + + - if profile_tab?(:followers) + #followers.tab-pane + -# This tab is always loaded via AJAX + + - if profile_tab?(:following) + #following.tab-pane + -# This tab is always loaded via AJAX + + .loading.hide + .gl-spinner.gl-spinner-md + + - if profile_tabs.empty? + .svg-content + = image_tag 'illustrations/profile_private_mode.svg' + .text-content.text-center + %h4 + - if @user.blocked? + = s_('UserProfile|This user is blocked') + - else + = s_('UserProfile|This user has a private profile') + .user-profile-sidebar + .profile-header.gl-py-5.gl-overflow-y-auto.gl-sm-pr-4 .gl-vertical-align-top.gl-text-left.gl-max-w-80.gl-overflow-wrap-anywhere .user-info - %h1.gl-font-size-h1.gl-line-height-1.gl-mb-1{ itemprop: 'name' } - = user_display_name(@user) - %h2.gl-font-size-h2.gl-text-gray-600.gl-font-weight-normal.gl-mt-0 - = @user.to_reference - - if !@user.blocked? && @user.confirmed? .gl-display-flex.gl-gap-4.gl-flex-direction-column - - if @user.pronouns.present? || @user.pronunciation.present? - .gl-font-sm - - if @user.pronunciation.present? - %p.gl-mb-0 - = s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation } - - if @user.pronouns.present? - %p.gl-mb-0 - = s_("UserProfile|Pronouns: %{pronouns}") % { pronouns: @user.pronouns } - - if @user.status&.customized? || @user.status&.busy? .cover-status.gl-font-sm.gl-border-l.gl-border-3.gl-px-3.gl-py-2.gl-bg-gray-10.gl-display-flex.gl-flex-direction-column.gl-gap-2 - if @user.status&.busy? @@ -159,72 +227,3 @@ = s_('UserProfile|Following') = gl_badge_tag @user.followees.count, size: :sm - .user-profile-content.gl-pt-6 - .cover-controls.gl-display-flex.gl-gap-3.gl-mb-4.gl-md-justify-content-end - = render 'users/follow_user' - -# The following edit button is mutually exclusive to the follow user button, they won't be shown together - - if @user == current_user - = render Pajamas::ButtonComponent.new(href: profile_path, - button_options: { title: s_('UserProfile|Edit profile') }) do - = s_("UserProfile|Edit profile") - = render 'users/view_gpg_keys' - = render 'users/view_user_in_admin_area' - .js-user-profile-actions{ data: user_profile_actions_data(@user) } - - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user) - #js-profile-tabs{ data: user_profile_tabs_app_data(@user) } - - unless Feature.enabled?(:profile_tabs_vue, current_user) - .tab-content.gl-overflow-hidden - - if profile_tab?(:overview) - #js-overview.tab-pane - = render "users/overview" - - - if profile_tab?(:activity) - #activity.tab-pane - .flash-container - - if can?(current_user, :read_cross_project) - %h4.gl-mt-0 - = s_('UserProfile|Most Recent Activity') - .content_list.user-activity-content{ data: { href: user_activity_path } } - .loading - = gl_loading_icon(size: 'md') - - unless @user.bot? - - if profile_tab?(:groups) - #groups.tab-pane - -# This tab is always loaded via AJAX - - - if profile_tab?(:contributed) - #contributed.tab-pane - -# This tab is always loaded via AJAX - - - if profile_tab?(:projects) - #projects.tab-pane - -# This tab is always loaded via AJAX - - - if profile_tab?(:starred) - #starred.tab-pane - -# This tab is always loaded via AJAX - - - if profile_tab?(:snippets) - #snippets.tab-pane - -# This tab is always loaded via AJAX - - - if profile_tab?(:followers) - #followers.tab-pane - -# This tab is always loaded via AJAX - - - if profile_tab?(:following) - #following.tab-pane - -# This tab is always loaded via AJAX - - .loading.hide - .gl-spinner.gl-spinner-md - - - if profile_tabs.empty? - .svg-content - = image_tag 'illustrations/profile_private_mode.svg' - .text-content.text-center - %h4 - - if @user.blocked? - = s_('UserProfile|This user is blocked') - - else - = s_('UserProfile|This user has a private profile') diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ce1a285a417acf..0cbde86a02bc81 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -52869,9 +52869,6 @@ msgstr "" msgid "UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!" msgstr "" -msgid "UserProfile|Most Recent Activity" -msgstr "" - msgid "UserProfile|No snippets found." msgstr "" diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb index e0c41155c2b42a..754de6ed67f280 100644 --- a/spec/features/users/show_spec.rb +++ b/spec/features/users/show_spec.rb @@ -305,7 +305,7 @@ end it 'shows user name as blocked' do - expect(page).to have_css(".user-info", text: 'Blocked user') + expect(page).to have_css(".user-profile-header", text: 'Blocked user') end it 'shows no additional fields' do @@ -343,7 +343,7 @@ end it 'shows user name as unconfirmed' do - expect(page).to have_css(".user-info", text: 'Unconfirmed user') + expect(page).to have_css(".user-profile-header", text: 'Unconfirmed user') end it 'shows no tab' do @@ -435,12 +435,6 @@ stub_feature_flags(profile_tabs_vue: false) end - it 'shows the most recent activity' do - subject - - expect(page).to have_content('Most Recent Activity') - end - context 'when external authorization is enabled' do before do enable_external_authorization_service_check -- GitLab From 52d40ce571085c9ada04b226e55bfb8845912965 Mon Sep 17 00:00:00 2001 From: Sascha Eggenberger Date: Thu, 14 Dec 2023 10:24:21 +0100 Subject: [PATCH 2/6] Visual adjustments Show profile information on top for overview page on small screens, show actions on right side Slightly adjusted profile picture size to match content --- .../stylesheets/page_bundles/profile.scss | 27 ++++++++++++------- app/views/users/show.html.haml | 6 ++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss index 1fbd0a7f2a5e55..b5e3e203fde83c 100644 --- a/app/assets/stylesheets/page_bundles/profile.scss +++ b/app/assets/stylesheets/page_bundles/profile.scss @@ -53,15 +53,6 @@ } } -.user-profile-image { - .gl-avatar { - @include media-breakpoint-up(md) { - height: 6.5rem; - width: 6.5rem; - } - } -} - // Middle dot divider between each element in a list of items. .middle-dot-divider { @include middle-dot-divider; @@ -260,3 +251,21 @@ // make contrib calendar scrollable overflow-x: auto; } + +// Home panel show profile sidebar +// information on top +.user-overview-page .user-profile { + @include media-breakpoint-down(sm) { + display: flex; + flex-wrap: wrap; + + .user-profile-content { + flex-basis: 100%; + } + + .user-profile-sidebar { + order: -1; + flex-basis: 100%; + } + } +} diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 39734b11f5e799..f0d23d64468fd1 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -14,7 +14,7 @@ %div{ class: container_class } .user-profile-header.gl-display-flex.gl-justify-content-space-between.gl-flex-direction-column.gl-md-flex-direction-row.gl-mt-5 - .gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row.gl-md-align-items-center.gl-column-gap-5 + .gl-display-flex.gl-flex-direction-row.gl-align-items-center.gl-column-gap-5.gl-mt-2.gl-sm-mt-0 = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', alt: 'View large avatar' do = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" }) %div @@ -32,7 +32,7 @@ %p.gl-mb-0 = s_("UserProfile|Pronouns: %{pronouns}") % { pronouns: @user.pronouns } %div - .cover-controls.gl-display-flex.gl-gap-3.gl-mb-4.gl-md-justify-content-end + .cover-controls.gl-display-flex.gl-gap-3.gl-mb-4.gl-justify-content-end = render 'users/follow_user' -# The following edit button is mutually exclusive to the follow user button, they won't be shown together - if @user == current_user @@ -49,7 +49,7 @@ - unless Feature.enabled?(:profile_tabs_vue, current_user) .tab-content.gl-overflow-hidden - if profile_tab?(:overview) - #js-overview.tab-pane + #js-overview.tab-pane.user-overview-page = render "users/overview" - if profile_tab?(:activity) -- GitLab From 8011d8fc77f4335a3ab01f96b106d5d2d7e44580 Mon Sep 17 00:00:00 2001 From: Sascha Eggenberger Date: Thu, 14 Dec 2023 13:20:34 +0100 Subject: [PATCH 3/6] More visual adjustments: - Changed avatar size to 64 - Changed sidebar size to match project page - Changed user actions to match project page - Minor tweaks --- .../stylesheets/page_bundles/profile.scss | 23 ++++++++----------- app/views/users/show.html.haml | 8 +++---- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss index b5e3e203fde83c..336076429154ce 100644 --- a/app/assets/stylesheets/page_bundles/profile.scss +++ b/app/assets/stylesheets/page_bundles/profile.scss @@ -125,16 +125,6 @@ } } - .cover-controls { - position: absolute; - top: $gl-padding-24; - right: -$gl-padding-8; - - @include media-breakpoint-up(lg) { - position: static; - } - } - .user-profile-nav { font-size: 0; } @@ -221,17 +211,24 @@ } } + .user-profile { position: relative; @include media-breakpoint-up(lg) { display: grid; - grid-template-columns: 3fr minmax(240px, 1fr); - gap: 3rem; + grid-template-columns: 3fr 290px; + gap: 2rem; + } +} + +.user-profile-header .cover-controls { + @include media-breakpoint-up(lg) { + margin-top: $gl-spacing-scale-3; } } -.user-profile-header > :first-child{ +.user-profile-header > :first-child { order: 2; @include media-breakpoint-up(md) { order: initial; diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index f0d23d64468fd1..26c5aab91dca30 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -14,17 +14,17 @@ %div{ class: container_class } .user-profile-header.gl-display-flex.gl-justify-content-space-between.gl-flex-direction-column.gl-md-flex-direction-row.gl-mt-5 - .gl-display-flex.gl-flex-direction-row.gl-align-items-center.gl-column-gap-5.gl-mt-2.gl-sm-mt-0 + .gl-display-flex.gl-flex-direction-row.gl-column-gap-5.gl-mt-2.gl-sm-mt-0 = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', alt: 'View large avatar' do - = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" }) + = render Pajamas::AvatarComponent.new(@user, alt: "", size: 64, avatar_options: { itemprop: "image" }) %div - %h1.gl-font-size-h1.gl-line-height-1.gl-mb-1.gl-mt-0{ itemprop: 'name' } + %h1.gl-font-size-h1.gl-line-height-1.gl-mb-1.gl-mt-0.gl-mr-2.gl-float-left{ itemprop: 'name' } = user_display_name(@user) %h2.gl-font-size-h2.gl-text-gray-600.gl-font-weight-normal.gl-my-0 = @user.to_reference - if !@user.blocked? && @user.confirmed? - if @user.pronouns.present? || @user.pronunciation.present? - .gl-font-sm.gl-mt-3 + .gl-font-sm.gl-text-secondary.gl-mt-2 - if @user.pronunciation.present? %p.gl-mb-0 = s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation } -- GitLab From e7edd044780b89b344c254b0248954fd31552618 Mon Sep 17 00:00:00 2001 From: Sascha Eggenberger Date: Thu, 14 Dec 2023 17:02:32 +0100 Subject: [PATCH 4/6] Use sidebar width variable --- app/assets/stylesheets/page_bundles/profile.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss index 336076429154ce..4edf29dcf0480b 100644 --- a/app/assets/stylesheets/page_bundles/profile.scss +++ b/app/assets/stylesheets/page_bundles/profile.scss @@ -217,7 +217,7 @@ @include media-breakpoint-up(lg) { display: grid; - grid-template-columns: 3fr 290px; + grid-template-columns: 3fr $right-sidebar-width; gap: 2rem; } } -- GitLab From fcbf4026d8e986b07dad88d88defb9d9c5299fa3 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Thu, 14 Dec 2023 13:29:37 -0700 Subject: [PATCH 5/6] Shuffle items around - Move pronouns and pronunciation to sidebar - Move status to header - Move busy badge to below avatar Changelog: changed --- .../stylesheets/page_bundles/profile.scss | 16 +++--- app/views/users/show.html.haml | 55 ++++++++++--------- locale/gitlab.pot | 7 ++- spec/features/profiles/account_spec.rb | 4 +- .../profiles/user_visits_profile_spec.rb | 2 +- .../user_uploads_avatar_to_profile_spec.rb | 2 +- spec/features/users/rss_spec.rb | 4 +- 7 files changed, 49 insertions(+), 41 deletions(-) diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss index 4edf29dcf0480b..bc173de5e2b9ce 100644 --- a/app/assets/stylesheets/page_bundles/profile.scss +++ b/app/assets/stylesheets/page_bundles/profile.scss @@ -53,6 +53,15 @@ } } +.user-profile-image { + .gl-avatar { + @include media-breakpoint-up(md) { + height: 6.5rem; + width: 6.5rem; + } + } +} + // Middle dot divider between each element in a list of items. .middle-dot-divider { @include middle-dot-divider; @@ -211,7 +220,6 @@ } } - .user-profile { position: relative; @@ -222,12 +230,6 @@ } } -.user-profile-header .cover-controls { - @include media-breakpoint-up(lg) { - margin-top: $gl-spacing-scale-3; - } -} - .user-profile-header > :first-child { order: 2; @include media-breakpoint-up(md) { diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 26c5aab91dca30..945bf885d133d8 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -13,24 +13,26 @@ = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") %div{ class: container_class } - .user-profile-header.gl-display-flex.gl-justify-content-space-between.gl-flex-direction-column.gl-md-flex-direction-row.gl-mt-5 - .gl-display-flex.gl-flex-direction-row.gl-column-gap-5.gl-mt-2.gl-sm-mt-0 - = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', alt: 'View large avatar' do - = render Pajamas::AvatarComponent.new(@user, alt: "", size: 64, avatar_options: { itemprop: "image" }) + .user-profile-header.gl-display-flex.gl-justify-content-space-between.gl-flex-direction-column.gl-md-flex-direction-row.gl-mt-5.gl-mb-2 + .gl-display-flex.gl-flex-direction-row.gl-md-align-items-center.gl-column-gap-5.gl-mt-2.gl-sm-mt-0 + .user-image.gl-relative.gl-py-2 + = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', alt: 'View large avatar' do + = render Pajamas::AvatarComponent.new(@user, alt: "", size: 64, avatar_options: { itemprop: "image" }) + - if @user.status&.busy? + = render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning', class: 'gl-absolute gl-display-flex gl-justify-content-center gl-align-items-center gl-bottom-0 gl-left-50p gl-bg-gray-50 gl-border gl-border-white gl-translate-x-n50') %div - %h1.gl-font-size-h1.gl-line-height-1.gl-mb-1.gl-mt-0.gl-mr-2.gl-float-left{ itemprop: 'name' } + %h1.gl-font-size-h1.gl-line-height-1.gl-mb-1.gl-mt-0.gl-mr-2{ itemprop: 'name' } = user_display_name(@user) %h2.gl-font-size-h2.gl-text-gray-600.gl-font-weight-normal.gl-my-0 = @user.to_reference - if !@user.blocked? && @user.confirmed? - - if @user.pronouns.present? || @user.pronunciation.present? - .gl-font-sm.gl-text-secondary.gl-mt-2 - - if @user.pronunciation.present? - %p.gl-mb-0 - = s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation } - - if @user.pronouns.present? - %p.gl-mb-0 - = s_("UserProfile|Pronouns: %{pronouns}") % { pronouns: @user.pronouns } + .gl-display-flex.gl-gap-4.gl-flex-direction-column.gl-my-2 + - if @user.status&.customized? + .cover-status.gl-font-sm.gl-border-l.gl-border-3.gl-px-3.gl-py-2.gl-display-flex.gl-flex-direction-column.gl-gap-2 + - if @user.status&.customized? + .gl-display-inline-flex.gl-gap-3.gl-align-items-center + = emoji_icon(@user.status.emoji) + = markdown_field(@user.status, :message) %div .cover-controls.gl-display-flex.gl-gap-3.gl-mb-4.gl-justify-content-end = render 'users/follow_user' @@ -106,19 +108,20 @@ .user-info - if !@user.blocked? && @user.confirmed? .gl-display-flex.gl-gap-4.gl-flex-direction-column - - if @user.status&.customized? || @user.status&.busy? - .cover-status.gl-font-sm.gl-border-l.gl-border-3.gl-px-3.gl-py-2.gl-bg-gray-10.gl-display-flex.gl-flex-direction-column.gl-gap-2 - - if @user.status&.busy? - %div - = render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning', class: 'gl-vertical-align-middle') - - if @user.status&.customized? - .gl-display-inline-flex.gl-gap-3.gl-align-items-baseline - = emoji_icon(@user.status.emoji) - = markdown_field(@user.status, :message) - - - if @user.bio.present? && @user.confirmed? && !@user.blocked? - %p.profile-user-bio.gl-mb-0 - = @user.bio + - if @user.pronouns.present? || @user.pronunciation.present? || @user.bio.present? + %div + %h3.h5.gl-mb-2= s_('UserProfile|About') + - if @user.pronouns.present? || @user.pronunciation.present? + .gl-mt-2.gl-mb-4 + - if @user.pronunciation.present? + %div= s_("UserProfile|Pronounced as:") + .gl-font-sm.gl-text-secondary= @user.pronunciation + - if @user.pronouns.present? + %div= s_("UserProfile|Pronouns:") + .gl-font-sm.gl-text-secondary= @user.pronouns + - if @user.bio.present? + %p.profile-user-bio.gl-mb-0 + = @user.bio - if @user.achievements_enabled && Ability.allowed?(current_user, :read_user_profile, @user) #js-user-achievements{ data: { root_url: root_url, user_id: @user.id } } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0cbde86a02bc81..0df5879f224824 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -52806,6 +52806,9 @@ msgstr "" msgid "UserProfile|%{id} ยท created %{created} by %{author}" msgstr "" +msgid "UserProfile|About" +msgstr "" + msgid "UserProfile|Activity" msgstr "" @@ -52878,10 +52881,10 @@ msgstr "" msgid "UserProfile|Personal projects" msgstr "" -msgid "UserProfile|Pronounced as: %{pronunciation}" +msgid "UserProfile|Pronounced as:" msgstr "" -msgid "UserProfile|Pronouns: %{pronouns}" +msgid "UserProfile|Pronouns:" msgstr "" msgid "UserProfile|Retry" diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index 7e4308106be635..08d9ec5f3a9f36 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -51,14 +51,14 @@ update_username(new_username) visit new_user_path expect(page).to have_current_path(new_user_path, ignore_query: true) - expect(find('.user-info')).to have_content(new_username) + expect(find('.user-profile-header')).to have_content(new_username) end it 'the old user path redirects to the new path' do update_username(new_username) visit old_user_path expect(page).to have_current_path(new_user_path, ignore_query: true) - expect(find('.user-info')).to have_content(new_username) + expect(find('.user-profile-header')).to have_content(new_username) end context 'with a project' do diff --git a/spec/features/profiles/user_visits_profile_spec.rb b/spec/features/profiles/user_visits_profile_spec.rb index 675c68da22fe18..9460cf1264416a 100644 --- a/spec/features/profiles/user_visits_profile_spec.rb +++ b/spec/features/profiles/user_visits_profile_spec.rb @@ -48,7 +48,7 @@ it 'shows expected content', :js do visit(user_path(user)) - page.within ".user-info" do + page.within ".user-profile-header" do expect(page).to have_content user.name expect(page).to have_content user.username end diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb index 5d121d9eeba9c9..bdad7781701b21 100644 --- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb @@ -51,7 +51,7 @@ visit user_path(user) - expect(page).to have_selector(%(img[src$="/uploads/-/system/user/avatar/#{user.id}/dk.png?width=96"])) + expect(page).to have_selector(%(img[src$="/uploads/-/system/user/avatar/#{user.id}/dk.png?width=64"])) # Cheating here to verify something that isn't user-facing, but is important expect(user.reload.avatar.file).to exist diff --git a/spec/features/users/rss_spec.rb b/spec/features/users/rss_spec.rb index 5fcaee0211d529..f0ca0715e145d6 100644 --- a/spec/features/users/rss_spec.rb +++ b/spec/features/users/rss_spec.rb @@ -13,7 +13,7 @@ end it 'shows the RSS link with overflow menu', :js do - page.within('.user-profile-content') do + page.within('.user-profile-header') do find_by_testid('base-dropdown-toggle').click end @@ -27,7 +27,7 @@ end it 'has an RSS without a feed token', :js do - page.within('.user-profile-content') do + page.within('.user-profile-header') do find_by_testid('base-dropdown-toggle').click end -- GitLab From 67b1e5195f263d4358fc78d21e5b5a657395e030 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Thu, 21 Dec 2023 13:48:29 -0700 Subject: [PATCH 6/6] Move sidebar content to top on mobile; other small fixes --- .../stylesheets/page_bundles/profile.scss | 24 +++++----- app/views/users/show.html.haml | 45 +++++++++---------- locale/gitlab.pot | 10 ++++- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/app/assets/stylesheets/page_bundles/profile.scss b/app/assets/stylesheets/page_bundles/profile.scss index bc173de5e2b9ce..8e314ef053148e 100644 --- a/app/assets/stylesheets/page_bundles/profile.scss +++ b/app/assets/stylesheets/page_bundles/profile.scss @@ -225,18 +225,11 @@ @include media-breakpoint-up(lg) { display: grid; - grid-template-columns: 3fr $right-sidebar-width; + grid-template-columns: 1fr $right-sidebar-width; gap: 2rem; } } -.user-profile-header > :first-child { - order: 2; - @include media-breakpoint-up(md) { - order: initial; - } -} - .user-profile-sidebar { z-index: 2; } @@ -253,13 +246,18 @@ // Home panel show profile sidebar // information on top -.user-overview-page .user-profile { - @include media-breakpoint-down(sm) { +.user-profile { + @include media-breakpoint-down(md) { display: flex; - flex-wrap: wrap; + flex-direction: column; - .user-profile-content { - flex-basis: 100%; + .user-overview-page { + display: flex; + flex-wrap: wrap; + + .user-profile-content { + flex-basis: 100%; + } } .user-profile-sidebar { diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 945bf885d133d8..8388ee16bfbc2e 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -13,28 +13,9 @@ = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") %div{ class: container_class } - .user-profile-header.gl-display-flex.gl-justify-content-space-between.gl-flex-direction-column.gl-md-flex-direction-row.gl-mt-5.gl-mb-2 - .gl-display-flex.gl-flex-direction-row.gl-md-align-items-center.gl-column-gap-5.gl-mt-2.gl-sm-mt-0 - .user-image.gl-relative.gl-py-2 - = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', alt: 'View large avatar' do - = render Pajamas::AvatarComponent.new(@user, alt: "", size: 64, avatar_options: { itemprop: "image" }) - - if @user.status&.busy? - = render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning', class: 'gl-absolute gl-display-flex gl-justify-content-center gl-align-items-center gl-bottom-0 gl-left-50p gl-bg-gray-50 gl-border gl-border-white gl-translate-x-n50') - %div - %h1.gl-font-size-h1.gl-line-height-1.gl-mb-1.gl-mt-0.gl-mr-2{ itemprop: 'name' } - = user_display_name(@user) - %h2.gl-font-size-h2.gl-text-gray-600.gl-font-weight-normal.gl-my-0 - = @user.to_reference - - if !@user.blocked? && @user.confirmed? - .gl-display-flex.gl-gap-4.gl-flex-direction-column.gl-my-2 - - if @user.status&.customized? - .cover-status.gl-font-sm.gl-border-l.gl-border-3.gl-px-3.gl-py-2.gl-display-flex.gl-flex-direction-column.gl-gap-2 - - if @user.status&.customized? - .gl-display-inline-flex.gl-gap-3.gl-align-items-center - = emoji_icon(@user.status.emoji) - = markdown_field(@user.status, :message) + .user-profile-header.gl-display-flex.gl-justify-content-space-between.gl-flex-direction-column.gl-sm-flex-direction-row-reverse.gl-mt-5.gl-mb-2 %div - .cover-controls.gl-display-flex.gl-gap-3.gl-mb-4.gl-justify-content-end + .cover-controls.gl-display-flex.gl-gap-3.gl-mb-4.gl-sm-justify-content-end = render 'users/follow_user' -# The following edit button is mutually exclusive to the follow user button, they won't be shown together - if @user == current_user @@ -44,6 +25,22 @@ = render 'users/view_gpg_keys' = render 'users/view_user_in_admin_area' .js-user-profile-actions{ data: user_profile_actions_data(@user) } + .gl-display-flex.gl-flex-direction-row.gl-md-align-items-center.gl-column-gap-5.gl-mt-2.gl-sm-mt-0 + .user-image.gl-relative.gl-py-2 + = link_to avatar_icon_for_user(@user, 400, current_user: current_user), class: "user-profile-image", target: '_blank', rel: 'noopener noreferrer', title: s_('UserProfile|View large avatar') do + = render Pajamas::AvatarComponent.new(@user, alt: s_('UserProfile|User profile picture'), size: 64, avatar_options: { itemprop: "image" }) + - if @user.status&.busy? + = render Pajamas::BadgeComponent.new(s_('UserProfile|Busy'), size: 'sm', variant: 'warning', class: 'gl-absolute gl-display-flex gl-justify-content-center gl-align-items-center gl-bottom-0 gl-left-50p gl-bg-gray-50 gl-border gl-border-white gl-translate-x-n50') + %div + %h1.gl-font-size-h1.gl-line-height-1.gl-mb-0.gl-mt-0.gl-mr-2{ itemprop: 'name' } + = user_display_name(@user) + .gl-font-size-h2.gl-text-gray-600.gl-font-weight-normal.gl-my-0 + = @user.to_reference + - if !@user.blocked? && @user.confirmed? && @user.status&.customized? + .gl-my-2.cover-status.gl-font-sm.gl-border-l.gl-border-3.gl-px-3.gl-py-2.gl-display-flex.gl-flex-direction-column + .gl-display-inline-flex.gl-gap-3.gl-align-items-center + = emoji_icon(@user.status.emoji) + = markdown_field(@user.status, :message) .user-profile .user-profile-content.gl-pt-5 - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user) @@ -114,11 +111,9 @@ - if @user.pronouns.present? || @user.pronunciation.present? .gl-mt-2.gl-mb-4 - if @user.pronunciation.present? - %div= s_("UserProfile|Pronounced as:") - .gl-font-sm.gl-text-secondary= @user.pronunciation + = sprintf(s_("UserProfile|Pronounced as: %{div_start}%{pronunciation}%{div_end}"), { pronunciation: @user.pronunciation, div_start: '
', div_end: '
' }).html_safe - if @user.pronouns.present? - %div= s_("UserProfile|Pronouns:") - .gl-font-sm.gl-text-secondary= @user.pronouns + = sprintf(s_("UserProfile|Pronouns: %{div_start}%{pronouns}%{div_end}"), { pronouns: @user.pronouns, div_start: '
', div_end: '
' }).html_safe - if @user.bio.present? %p.profile-user-bio.gl-mb-0 = @user.bio diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0df5879f224824..f5e9048fdeb8e9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -52881,10 +52881,10 @@ msgstr "" msgid "UserProfile|Personal projects" msgstr "" -msgid "UserProfile|Pronounced as:" +msgid "UserProfile|Pronounced as: %{div_start}%{pronunciation}%{div_end}" msgstr "" -msgid "UserProfile|Pronouns:" +msgid "UserProfile|Pronouns: %{div_start}%{pronouns}%{div_end}" msgstr "" msgid "UserProfile|Retry" @@ -52947,9 +52947,15 @@ msgstr "" msgid "UserProfile|User profile navigation" msgstr "" +msgid "UserProfile|User profile picture" +msgstr "" + msgid "UserProfile|View all" msgstr "" +msgid "UserProfile|View large avatar" +msgstr "" + msgid "UserProfile|View user in admin area" msgstr "" -- GitLab