[REF] mail: chatter topbar styles

The Chatter's topbar (containing the buttons like 'Send Message', 'Log
Note') was difficult to deal with: specially the positioning of its
content (a float into another float...).

So, this commit refactors the topbar's layout using Flexbox. It allows
to simplify and reduce the amount of (S)CSS needed to achieve the same
visual result.

In the process, the Followers (dropdown) buttons now use correctly
nested .btn-group components (as described by the Bootstrap 4
documentation) and SubTypes dropdown items use semantic html element
(<button>) instead of attaching behavior on icon element(<i>).

Finally a few Chatter's tests requested a slight adaptation (cf.
trimming element's textual content).

Task ID: 1928573

closes odoo/odoo#33823

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Pierre Paridans
2019-06-04 13:47:33 +00:00
parent b415da5daa
commit ece2fed154
5 changed files with 113 additions and 193 deletions
@@ -1,8 +1,5 @@
.oe_chatter {
.btn.o_active_attach {
height: 300px;
}
.o_mail_chatter_attachments {
min-height: 50px;
+15 -55
View File
@@ -1,75 +1,35 @@
// Default chatter layout.
// Extended in enterprise by form_view.less to achieve the side-chatter
.o_chatter {
width: 100%;
padding-top: 0!important;
.o_spinner {
text-align: center;
font-size: large;
}
.o_chatter_topbar {
height: $o-statusbar-height;
position: relative;
margin: $grid-gutter-width*0.5 0 0;
padding: 0;
display: flex;
border-bottom: $nav-tabs-border-width solid transparent;
> .o_topbar_right_area {
border-bottom: 1px solid transparent;
position: relative;
float: right;
flex: 1 1 auto;
height: $o-statusbar-height;
.o_chatter_button_attachment {
height: $o-statusbar-height;
float: right;
margin-right: 25px;
.fa-paperclip, .o_chatter_attachment_button_count {
font-weight: bold;
}
}
.o_followers {
height: $o-statusbar-height;
border-bottom: 1px solid transparent;
flex: 0 1 auto;
}
}
> .btn {
height: $o-statusbar-height;
border: 1px solid transparent;
}
.btn {
@extend .text-nowrap;
padding-right: $btn-padding-x;
padding-left: $btn-padding-x;
margin-bottom: -$nav-tabs-border-width;
padding: $grid-gutter-width*0.25 - $nav-tabs-border-width $grid-gutter-width*0.5 $grid-gutter-width*0.25;
border-radius: $border-radius-sm $border-radius-sm 0 0;
}
> .o_topbar_right_area {
display: flex;
margin-left: auto;
justify-content: flex-end;
}
}
&.o_chatter_composer_active .o_chatter_topbar {
> .btn, > .o_followers, > .o_topbar_right_area{
border-radius: $border-radius-sm $border-radius-sm 0 0;
border-width: 0 0 1px;
border-bottom-color: gray('300');
border-bottom-color: gray('300');
&.o_active {
color: $o-brand-odoo;
background-color: theme-color('light');
border-color: gray('300');
border-width: 1px 1px 0;
}
}
}
}
@include media-breakpoint-down(sm) {
.o_chatter .o_chatter_topbar > .o_topbar_right_area {
.o_chatter_button_attachment {
margin-right: initial;
.btn.o_active {
color: $o-brand-odoo;
background-color: theme-color('light');
border: $nav-tabs-border-width solid gray('300');
border-bottom-color: transparent;
}
}
}
+61 -105
View File
@@ -1,134 +1,90 @@
.o_followers {
float: right;
@include media-breakpoint-down(sm) {
display: none !important; // Hide the followers in mobile
display: flex;
justify-content: flex-end;
order: 1;
&.o_field_widget {
margin-bottom: initial;
}
.o_followers_actions {
position: relative;
float: right;
> .o_followers_title_box {
order: 1;
}
.dropdown-toggle {
opacity: 0.3;
border: none;
.o_followers_follow_button {
color: $body-color;
font-weight: bold;
text-align: right;
.o_follow, .o_followers_unfollow, .o_followers_following {
display: none;
&:hover, &:focus, &[aria-expanded="true"] {
opacity: 1;
}
> .fa {
font-size: inherit;
}
&.o_followers_following {
display: block;
}
}
&:hover .dropdown-toggle {
opacity: 1;
// when following, show 'following'
&.o_followers_following .o_followers_following {
display: initial;
}
.o_followers_follow_button {
padding-right: 0;
color: $body-color;
font-weight: bold;
.o_follow, .o_followers_unfollow, .o_followers_following {
// when following and hovering, show 'unfollow'
&.o_followers_following:hover {
.o_followers_following {
display: none;
}
// when following, show 'following'
&.o_followers_following .o_followers_following {
display: inline;
}
// when following and hovering, show 'unfollow'
&.o_followers_following:hover .o_followers_following {
display: none;
}
&.o_followers_following:hover .o_followers_unfollow {
display: inline;
}
// when not following show 'follow'
&.o_followers_notfollow .o_follow {
display: inline;
}
.fa {
&.fa-times {
color: theme-color('warning');
}
&.fa-check {
color: theme-color('success');
}
.o_followers_unfollow {
display: initial;
}
}
.o_subtype {
padding-left: 10px;
// when not following show 'follow'
&.o_followers_notfollow .o_follow {
display: initial;
}
.fa {
&.fa-times {
color: theme-color('warning');
}
&.fa-check {
color: theme-color('success');
}
}
}
.o_followers_title_box {
position: relative;
float: right;
margin-left: 25px;
.o_followers_list {
width: 20vh;
max-height: 50vh;
overflow: auto;
}
.dropdown-toggle {
.o_followers_count {
padding-right: 5px;
font-weight: bold;
.o_followers_title_box .dropdown-item.o_partner {
padding: 0;
display: flex;
align-items: center;
.o_mail_redirect {
margin-right: auto;
color: $dropdown-link-color;
img {
width: $o-mail-partner-avatar-size;
}
}
.o_followers_list {
font-size: small;
max-height: 50vh; // ancestor has size 33px
overflow: auto;
.btn {
padding: 0 $grid-gutter-width*0.25;
}
.o_partner {
position: relative; // required for old design compatibility
&.o_inactive {
.o_mail_redirect {
color: $gray-500;
font-style: italic;
> a {
max-width: 160px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: $o-mail-partner-avatar-size;
padding: 3px $o-mail-partner-avatar-size + 8px;
}
> img {
@include o-position-absolute($top: 0, $left: 0);
width: $o-mail-partner-avatar-size;
}
.o_remove_follower {
@include o-position-absolute(6px, 5px);
cursor: pointer;
}
.o_edit_subtype {
@include o-position-absolute(6px, 18px);
cursor: pointer;
}
&.o_inactive {
> a {
color: $gray-500;
font-style: italic;
}
> img {
opacity: 0.25;
}
img {
opacity: 0.25;
}
}
}
}
}
// Edit subtypes in dialog
.modal .modal-body > ul {
padding-left: 0;
> li.o_subtype {
list-style: none;
}
}
+34 -27
View File
@@ -5,8 +5,8 @@
Followers, actions and subtypes in a record.
-->
<t t-name="mail.Followers">
<div class="o_followers">
<div class="o_followers_title_box">
<div class="o_followers btn-group">
<div class="o_followers_title_box btn-group">
<button class="btn btn-link dropdown-toggle" title="Dropdown menu - Followers"
data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-user" role="img" aria-label="Dropdown menu - Followers"></i>
@@ -14,15 +14,16 @@
</button>
<div class="dropdown-menu dropdown-menu-right o_followers_list" role="menu"/>
</div>
<div class="o_followers_actions">
<div class="btn-group o_subtypes_list">
<button class="btn btn-link o_followers_follow_button o_followers_notfollow">
<span class="o_follow">Follow</span>
<span class="fa fa-times o_followers_unfollow"/>
<span class="o_followers_unfollow"> Unfollow</span>
<span class="fa fa-check o_followers_following"/>
<span class="o_followers_following"> Following</span>
</button><button class="btn btn-link dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<div class="o_followers_actions btn-group">
<button class="btn btn-link o_followers_follow_button o_followers_notfollow">
<span class="o_follow">Follow</span>
<i class="fa fa-times o_followers_unfollow"/>
<span class="o_followers_unfollow"> Unfollow</span>
<i class="fa fa-check o_followers_following"/>
<span class="o_followers_following"> Following</span>
</button>
<div class="o_subtypes_list btn-group">
<button class="btn btn-link dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="fa fa-bell" role="img" aria-label="Alarm menu" title="Alarm menu"/>
</button>
<div class="dropdown-menu dropdown-menu-right" role="menu"/>
@@ -35,22 +36,28 @@
Partner or channel following the record
-->
<t t-name="mail.Followers.partner">
<div role="menuitem" t-attf-class="o_partner {{ !record.active ? 'o_inactive': '' }}">
<a class="dropdown-item o_mail_redirect"
href="#"
t-att-title="record.title"
t-att-data-oe-model="record.res_model"
t-att-data-oe-id="record.res_id"><t t-esc="record.name"/></a>
<img t-att-src="record.avatar_url" alt="Avatar"/>
<i t-if="record.is_editable" class="fa fa-pencil o_edit_subtype d-none"
title="Edit subscription"
aria-label="Edit subscription" role="img"
t-att-data-follower-id="record.id"
t-att-data-oe-id="record.res_id"
t-att-data-oe-model="record.res_model"/>
<i t-if="widget.isEditable" class="fa fa-remove o_remove_follower"
aria-label="Remove this follower" role="img"
title="Remove this follower"/>
<div role="menuitem" t-attf-class="dropdown-item o_partner {{ !record.active ? 'o_inactive': '' }}">
<a class="o_mail_redirect text-truncate"
href="#"
t-att-title="record.title"
t-att-data-oe-model="record.res_model"
t-att-data-oe-id="record.res_id">
<img t-att-src="record.avatar_url" alt="Avatar"/>
<t t-esc="record.name"/>
</a>
<button t-if="record.is_editable"
class="btn btn-icon fa fa-pencil o_edit_subtype d-none"
title="Edit subscription"
aria-label="Edit subscription"
role="img"
t-att-data-follower-id="record.id"
t-att-data-oe-id="record.res_id"
t-att-data-oe-model="record.res_model"/>
<button t-if="widget.isEditable"
class="btn btn-icon fa fa-remove o_remove_follower"
aria-label="Remove this follower"
role="img"
title="Remove this follower"/>
</div>
</t>
+3 -3
View File
@@ -2638,7 +2638,7 @@ QUnit.test('chatter: suggested partner auto-follow on message post', async funct
"should have a single follower (widget counter)");
assert.containsOnce(form, '.o_followers_list > div.o_partner',
"should have a single follower (listed partners)");
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a').text(), "Admin",
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a').text().trim(), "Admin",
"should have 'Admin' as follower");
// open composer
@@ -2665,10 +2665,10 @@ QUnit.test('chatter: suggested partner auto-follow on message post', async funct
"should have a two followers (widget counter)");
assert.containsN(form, '.o_followers_list > div.o_partner', 2,
"should have two followers (listed partners)");
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a[data-oe-id="5"]').text(),
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a[data-oe-id="5"]').text().trim(),
"Admin",
"should have 'Admin' as follower");
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a[data-oe-id="8"]').text(),
assert.strictEqual(form.$('.o_followers_list > div.o_partner > a[data-oe-id="8"]').text().trim(),
"Demo User",
"should have 'Demo User' as follower");