Commit f6f949f4 authored by Jacob Schatz's avatar Jacob Schatz Committed by Rémy Coutable

Merge branch 'improved-issue-sidebar' into 'master'

Improved issue sidebar

Updated the spacing throughout the sidebar so that it fits better on smaller screens. Also adds a more participants button to show any other participants after the first row.

Closes #13353

See merge request !3097
parent 1dc218ed
...@@ -7,6 +7,7 @@ class @Issue ...@@ -7,6 +7,7 @@ class @Issue
# Prevent duplicate event bindings # Prevent duplicate event bindings
@disableTaskList() @disableTaskList()
@fixAffixScroll() @fixAffixScroll()
@initParticipants()
if $('a.btn-close').length if $('a.btn-close').length
@initTaskList() @initTaskList()
@initIssueBtnEventListeners() @initIssueBtnEventListeners()
...@@ -84,3 +85,27 @@ class @Issue ...@@ -84,3 +85,27 @@ class @Issue
type: 'PATCH' type: 'PATCH'
url: $('form.js-issuable-update').attr('action') url: $('form.js-issuable-update').attr('action')
data: patchData data: patchData
initParticipants: ->
_this = @
$(document).on "click", ".js-participants-more", @toggleHiddenParticipants
$(".js-participants-author").each (i) ->
if i >= _this.PARTICIPANTS_ROW_COUNT
$(@)
.addClass "js-participants-hidden"
.hide()
toggleHiddenParticipants: (e) ->
e.preventDefault()
currentText = $(this).text().trim()
lessText = $(this).data("less-text")
originalText = $(this).data("original-text")
if currentText is originalText
$(this).text(lessText)
else
$(this).text(originalText)
$(".js-participants-hidden").toggle()
@media (max-width: $screen-sm-max) {
.issuable-affix {
margin-top: 20px;
}
}
@media (max-width: $screen-md-max) {
.issuable-affix {
position: static;
}
}
@media (min-width: $screen-md-max) {
.issuable-affix {
&.affix-top {
position: static;
}
&.affix {
position: fixed;
top: 70px;
margin-right: 35px;
&.no-affix {
position: relative;
top: 0;
}
}
}
}
.issuable-details { .issuable-details {
section { section {
.issuable-discussion { .issuable-discussion {
...@@ -54,6 +23,10 @@ ...@@ -54,6 +23,10 @@
padding: 6px 10px; padding: 6px 10px;
} }
} }
&.has-labels {
margin-bottom: -5px;
}
} }
.issuable-sidebar { .issuable-sidebar {
...@@ -66,8 +39,9 @@ ...@@ -66,8 +39,9 @@
width: $gutter_inner_width; width: $gutter_inner_width;
// -- // --
&:first-child { &.issuable-sidebar-header {
padding-top: 5px; padding-top: 0;
padding-bottom: 10px;
} }
&:last-child { &:last-child {
...@@ -75,7 +49,6 @@ ...@@ -75,7 +49,6 @@
} }
span { span {
margin-top: 7px;
display: inline-block; display: inline-block;
} }
...@@ -84,7 +57,7 @@ ...@@ -84,7 +57,7 @@
} }
.issuable-count { .issuable-count {
margin-top: 7px;
} }
.gutter-toggle { .gutter-toggle {
...@@ -99,19 +72,19 @@ ...@@ -99,19 +72,19 @@
.title { .title {
color: $gl-text-color; color: $gl-text-color;
margin-bottom: 8px; margin-bottom: 10px;
line-height: 1;
.avatar { .avatar {
margin-left: 0; margin-left: 0;
} }
label {
font-weight: normal;
margin-right: 4px;
}
.edit-link { .edit-link {
color: $gl-gray; color: $gl-gray;
&:hover {
color: $md-link-color;
}
} }
} }
...@@ -144,11 +117,6 @@ ...@@ -144,11 +117,6 @@
.btn-clipboard { .btn-clipboard {
color: $gl-gray; color: $gl-gray;
} }
.participants .avatar {
margin-top: 6px;
margin-right: 2px;
}
} }
.right-sidebar { .right-sidebar {
...@@ -163,8 +131,12 @@ ...@@ -163,8 +131,12 @@
&.right-sidebar-expanded { &.right-sidebar-expanded {
width: $gutter_width; width: $gutter_width;
hr { .value {
display: none; line-height: 1;
}
.bold {
font-weight: 600;
} }
.sidebar-collapsed-icon { .sidebar-collapsed-icon {
...@@ -172,8 +144,23 @@ ...@@ -172,8 +144,23 @@
} }
.gutter-toggle { .gutter-toggle {
margin-top: 7px;
border-left: 1px solid $border-gray-light; border-left: 1px solid $border-gray-light;
} }
.assignee .avatar {
float: left;
margin-right: 10px;
margin-bottom: 0;
margin-left: 0;
}
.username {
display: block;
margin-top: 4px;
font-size: 13px;
font-weight: normal;
}
} }
.subscribe-button { .subscribe-button {
...@@ -193,14 +180,6 @@ ...@@ -193,14 +180,6 @@
width: $sidebar_collapsed_width; width: $sidebar_collapsed_width;
padding-top: 0; padding-top: 0;
hr {
margin: 0;
color: $gray-normal;
border-color: $gray-normal;
width: 62px;
margin-left: -20px
}
.block { .block {
width: $sidebar_collapsed_width - 1px; width: $sidebar_collapsed_width - 1px;
margin-left: -19px; margin-left: -19px;
...@@ -209,12 +188,18 @@ ...@@ -209,12 +188,18 @@
overflow: hidden; overflow: hidden;
} }
.participants {
border-bottom: 1px solid $border-gray-light;
}
.hide-collapsed { .hide-collapsed {
display: none; display: none;
} }
.gutter-toggle { .gutter-toggle {
margin-left: -36px; width: 100%;
margin-left: 0;
padding-left: 25px;
} }
.sidebar-collapsed-icon { .sidebar-collapsed-icon {
...@@ -229,6 +214,10 @@ ...@@ -229,6 +214,10 @@
margin-top: 0; margin-top: 0;
} }
.author {
display: none;
}
.btn-clipboard { .btn-clipboard {
border: none; border: none;
...@@ -241,6 +230,11 @@ ...@@ -241,6 +230,11 @@
} }
} }
} }
.sidebar-collapsed-user {
padding-bottom: 0;
margin-bottom: 10px;
}
} }
.btn { .btn {
...@@ -251,6 +245,13 @@ ...@@ -251,6 +245,13 @@
border: 1px solid $border-gray-dark; border: 1px solid $border-gray-dark;
} }
} }
a:not(.btn) {
&:hover {
color: $md-link-color;
text-decoration: none;
}
}
} }
.btn-default.gutter-toggle { .btn-default.gutter-toggle {
...@@ -270,3 +271,29 @@ ...@@ -270,3 +271,29 @@
color: $gray-darkest; color: $gray-darkest;
} }
} }
.participants-list {
margin: -5px -5px;
}
.participants-author {
display: inline-block;
padding: 5px 5px;
.author_link {
display: block;
}
.avatar.avatar-inline {
margin: 0;
}
}
.participants-more {
margin-top: 5px;
margin-left: 5px;
a {
color: #8c8c8c;
}
}
...@@ -26,7 +26,7 @@ module ProjectsHelper ...@@ -26,7 +26,7 @@ module ProjectsHelper
image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar] image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
end end
def link_to_member(project, author, opts = {}) def link_to_member(project, author, opts = {}, &block)
default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" } default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" }
opts = default_opts.merge(opts) opts = default_opts.merge(opts)
...@@ -44,6 +44,8 @@ module ProjectsHelper ...@@ -44,6 +44,8 @@ module ProjectsHelper
author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name] author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name]
end end
author_html << capture(&block) if block
author_html = author_html.html_safe author_html = author_html.html_safe
if opts[:name] if opts[:name]
......
- participants_row = 7
- participants_size = participants.size
- participants_extra = participants_size - participants_row
.block.participants .block.participants
.sidebar-collapsed-icon .sidebar-collapsed-icon
= icon('users') = icon('users')
...@@ -5,6 +8,13 @@ ...@@ -5,6 +8,13 @@
= participants.count = participants.count
.title.hide-collapsed .title.hide-collapsed
= pluralize participants.count, "participant" = pluralize participants.count, "participant"
- participants.each do |participant| .hide-collapsed.participants-list
%span.hide-collapsed - participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24) .participants-author.js-participants-author
= link_to_member(@project, participant, name: false, size: 24)
- if participants_extra > 0
%div.participants-more
%a.js-participants-more{href: "#", data: {original_text: "+ #{participants_size - 7} more", less_text: "- show less"}}
+ #{participants_extra} more
:javascript
Issue.prototype.PARTICIPANTS_ROW_COUNT = #{participants_row};
%aside.right-sidebar{ class: sidebar_gutter_collapsed_class } %aside.right-sidebar{ class: sidebar_gutter_collapsed_class }
.issuable-sidebar .issuable-sidebar
.block .block.issuable-sidebar-header
%span.issuable-count.hide-collapsed.pull-left %span.issuable-count.hide-collapsed.pull-left
= issuable.iid = issuable.iid
of of
= issuables_count(issuable) = issuables_count(issuable)
%span.pull-right %a.gutter-toggle.pull-right.js-sidebar-toggle{href: '#'}
%a.gutter-toggle.js-sidebar-toggle{href: '#'} = sidebar_gutter_toggle_icon
= sidebar_gutter_toggle_icon
.issuable-nav.hide-collapsed.pull-right.btn-group{role: 'group', "aria-label" => '...'} .issuable-nav.hide-collapsed.pull-right.btn-group{role: 'group', "aria-label" => '...'}
- if prev_issuable = prev_issuable_for(issuable) - if prev_issuable = prev_issuable_for(issuable)
= link_to 'Prev', [@project.namespace.becomes(Namespace), @project, prev_issuable], class: 'btn btn-default prev-btn' = link_to 'Prev', [@project.namespace.becomes(Namespace), @project, prev_issuable], class: 'btn btn-default prev-btn'
...@@ -22,20 +21,20 @@ ...@@ -22,20 +21,20 @@
= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f| = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
.block.assignee .block.assignee
.sidebar-collapsed-icon .sidebar-collapsed-icon.sidebar-collapsed-user{data: {toggle: "tooltip", placement: "left", container: "body"}, title: (issuable.assignee.to_reference if issuable.assignee)}
- if issuable.assignee - if issuable.assignee
= link_to_member_avatar(issuable.assignee, size: 24) = link_to_member(@project, issuable.assignee, size: 24)
- else - else
= icon('user') = icon('user')
.title.hide-collapsed .title.hide-collapsed
%label Assignee
Assignee
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.pull-right = link_to 'Edit', '#', class: 'edit-link pull-right'
= link_to 'Edit', '#', class: 'edit-link' .value.bold.hide-collapsed
.value.hide-collapsed
- if issuable.assignee - if issuable.assignee
%strong= link_to_member(@project, issuable.assignee, size: 24) = link_to_member(@project, issuable.assignee, size: 32) do
%span.username
= issuable.assignee.to_reference
- if issuable.instance_of?(MergeRequest) && !issuable.can_be_merged_by?(issuable.assignee) - if issuable.instance_of?(MergeRequest) && !issuable.can_be_merged_by?(issuable.assignee)
%a.pull-right.cannot-be-merged{href: '#', data: {toggle: 'tooltip'}, title: 'Not allowed to merge'} %a.pull-right.cannot-be-merged{href: '#', data: {toggle: 'tooltip'}, title: 'Not allowed to merge'}
= icon('exclamation-triangle') = icon('exclamation-triangle')
...@@ -54,18 +53,13 @@ ...@@ -54,18 +53,13 @@
- else - else
No No
.title.hide-collapsed .title.hide-collapsed
%label Milestone
Milestone
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.pull-right = link_to 'Edit', '#', class: 'edit-link pull-right'
= link_to 'Edit', '#', class: 'edit-link' .value.bold.hide-collapsed
.value.hide-collapsed
- if issuable.milestone - if issuable.milestone
%span.back-to-milestone = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
= link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do = issuable.milestone.title
%strong
= icon('clock-o')
= issuable.milestone.title
- else - else
.light None .light None
.selectbox.hide-collapsed .selectbox.hide-collapsed
...@@ -80,11 +74,10 @@ ...@@ -80,11 +74,10 @@
%span %span
= issuable.labels.count = issuable.labels.count
.title.hide-collapsed .title.hide-collapsed
%label Labels Labels
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.pull-right = link_to 'Edit', '#', class: 'edit-link pull-right'
= link_to 'Edit', '#', class: 'edit-link' .value.issuable-show-labels.hide-collapsed{class: ("has-labels" if issuable.labels.any?)}
.value.issuable-show-labels.hide-collapsed
- if issuable.labels.any? - if issuable.labels.any?
- issuable.labels.each do |label| - issuable.labels.each do |label|
= link_to_label(label, type: issuable.to_ability_name) = link_to_label(label, type: issuable.to_ability_name)
...@@ -95,14 +88,13 @@ ...@@ -95,14 +88,13 @@
{ selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" } { selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" }
= render "shared/issuable/participants", participants: issuable.participants(current_user) = render "shared/issuable/participants", participants: issuable.participants(current_user)
%hr
- if current_user - if current_user
- subscribed = issuable.subscribed?(current_user) - subscribed = issuable.subscribed?(current_user)
.block.light.subscription{data: {url: toggle_subscription_path(issuable)}} .block.light.subscription{data: {url: toggle_subscription_path(issuable)}}
.sidebar-collapsed-icon .sidebar-collapsed-icon
= icon('rss') = icon('rss')
.title.hide-collapsed .title.hide-collapsed
%label.light Notifications Notifications
- subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed' - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
%button.btn.btn-block.btn-gray.subscribe-button.hide-collapsed{:type => 'button'} %button.btn.btn-block.btn-gray.subscribe-button.hide-collapsed{:type => 'button'}
%span= subscribed ? 'Unsubscribe' : 'Subscribe' %span= subscribed ? 'Unsubscribe' : 'Subscribe'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment