- @hide_top_links = true - @hide_breadcrumbs = true - @no_container = true - page_title user_display_name(@user) - page_description @user.bio unless @user.blocked? || !@user.confirmed? - page_itemtype 'http://schema.org/Person' - add_page_specific_style 'page_bundles/profile' - link_classes = "flex-grow-1 mx-1 " = content_for :meta_tags do = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") .user-profile .cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty?)] } = render layout: 'users/cover_controls' do - if @user == current_user = link_to profile_path, class: link_classes + 'btn gl-button btn-default btn-icon has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = sprite_icon('pencil') - elsif current_user - if @user.abuse_report %button{ class: link_classes + 'btn gl-button btn-danger btn-icon', title: s_('UserProfile|Already reported for abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } }> = sprite_icon('error') - else = link_to new_abuse_report_path(user_id: @user.id, ref_url: request.referer), class: link_classes + 'btn gl-button btn-default btn-icon', title: s_('UserProfile|Report abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = sprite_icon('error') - verified_gpg_keys = @user.gpg_keys.select(&:verified?) - if verified_gpg_keys.any? = link_to user_gpg_keys_path, class: link_classes + 'btn btn-default btn-md gl-button btn-icon has-tooltip', title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = sprite_icon('key', css_class: 'gl-button-icon gl-icon') - if can?(current_user, :read_user_profile, @user) = link_to user_path(@user, rss_url_options), class: link_classes + 'btn gl-button btn-default btn-icon has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do = sprite_icon('rss', css_class: 'qa-rss-icon') - if current_user && current_user.admin? = link_to [:admin, @user], class: link_classes + 'btn gl-button btn-default btn-icon', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = sprite_icon('user') - if current_user && current_user.id != @user.id - if current_user.following?(@user) = form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do = render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-w-full', data: { track_action: 'click_button', track_label: 'unfollow_from_profile' } }) do = _('Unfollow') - else = form_tag user_follow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do = render Pajamas::ButtonComponent.new(variant: :confirm, type: :submit, button_options: { class: 'gl-w-full', data: { qa_selector: 'follow_user_link', track_action: 'click_button', track_label: 'follow_from_profile' } }) do = _('Follow') .profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] } .avatar-holder = link_to avatar_icon_for_user(@user, 400, current_user: current_user), target: '_blank', rel: 'noopener noreferrer' do = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" }) - if @user.blocked? || !@user.confirmed? .user-info .cover-title = user_display_name(@user) = render "users/profile_basic_info" - else .user-info .cover-title{ itemprop: 'name' } = @user.name - if @user.pronouns.present? %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle = "(#{@user.pronouns})" - if @user.status&.busy? %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)") - if @user.pronunciation.present? .gl-align-items-center %p.gl-mb-4.gl-text-gray-500= s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation } - if @user.status&.customized? .cover-status.gl-display-inline-flex.gl-align-items-center = emoji_icon(@user.status.emoji, class: 'gl-mr-2') = markdown_field(@user.status, :message) = render "users/profile_basic_info" .gl-text-gray-900.mb-1.mb-sm-2 - unless @user.location.blank? = render 'middle_dot_divider', stacking: true, itemprop: 'address', itemscope: true, itemtype: 'https://schema.org/PostalAddress' do = sprite_icon('location', css_class: 'fgray') %span{ itemprop: 'addressLocality' } = @user.location - user_local_time = local_time(@user.timezone) - unless user_local_time.nil? = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do = sprite_icon('clock', css_class: 'fgray') %span = user_local_time - unless work_information(@user).blank? = render 'middle_dot_divider', stacking: true do = sprite_icon('work', css_class: 'fgray') %span = work_information(@user, with_schema_markup: true) .gl-text-gray-900 - unless @user.skype.blank? = render 'middle_dot_divider' do = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do = sprite_icon('skype', css_class: 'skype-icon') - unless @user.linkedin.blank? = render 'middle_dot_divider' do = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do = sprite_icon('linkedin', css_class: 'linkedin-icon') - unless @user.twitter.blank? = render 'middle_dot_divider', breakpoint: 'sm' do = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do = sprite_icon('twitter', css_class: 'twitter-icon') - unless @user.website_url.blank? = render 'middle_dot_divider', stacking: true do - if Feature.enabled?(:security_auto_fix) && @user.bot? = sprite_icon('question', css_class: 'gl-text-blue-600') = link_to @user.short_website_url, @user.full_website_url, target: '_blank', rel: 'me noopener noreferrer nofollow', itemprop: 'url' - if display_public_email?(@user) = render 'middle_dot_divider', stacking: true do = link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email' .gl-text-gray-900 = sprite_icon('users', css_class: 'gl-vertical-align-middle gl-text-gray-500') = render 'middle_dot_divider' do = link_to user_followers_path do - count = @user.followers.count = n_('1 follower', '%{count} followers', count) % { count: count } = render 'middle_dot_divider' do = link_to user_following_path, data: { qa_selector: 'following_link' } do = @user.followees.count = _('following') - if @user.bio.present? .gl-text-gray-900 .profile-user-bio = @user.bio - unless profile_tabs.empty? .scrolling-tabs-container .fade-left= sprite_icon('chevron-lg-left', size: 12) .fade-right= sprite_icon('chevron-lg-right', size: 12) %ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs - if profile_tab?(:overview) %li.js-overview-tab = link_to user_path, data: { target: 'div#js-overview', action: 'overview', toggle: 'tab' } do = s_('UserProfile|Overview') - if profile_tab?(:activity) %li.js-activity-tab = link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do = s_('UserProfile|Activity') - unless Feature.enabled?(:security_auto_fix) && @user.bot? - if profile_tab?(:groups) %li.js-groups-tab = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do = s_('UserProfile|Groups') - if profile_tab?(:contributed) %li.js-contributed-tab = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do = s_('UserProfile|Contributed projects') - if profile_tab?(:projects) %li.js-projects-tab = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do = s_('UserProfile|Personal projects') - if profile_tab?(:starred) %li.js-starred-tab = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do = s_('UserProfile|Starred projects') - if profile_tab?(:snippets) %li.js-snippets-tab = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do = s_('UserProfile|Snippets') - if profile_tab?(:followers) %li.js-followers-tab = link_to user_followers_path, data: { target: 'div#followers', action: 'followers', toggle: 'tab', endpoint: user_followers_path(format: :json) } do = s_('UserProfile|Followers') - if profile_tab?(:following) %li.js-following-tab = link_to user_following_path, data: { target: 'div#following', action: 'following', toggle: 'tab', endpoint: user_following_path(format: :json) } do = s_('UserProfile|Following') %div{ class: container_class } .tab-content - 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.prepend-top-20 = s_('UserProfile|Most Recent Activity') .content_list{ 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')