[IMP] web,hr_holiday: improve calendar filter panel

We replaced the customized checkboxes with the original input element
with `.form-check-input` whilst still using the custom colors for more
consistency accross modules.

Avatars have the .o_avatar class added to them which allows us to resize
them with the CSS variable.
And SCSS has been replaced with utility classes where possible.

This commit has been moved here from
PR https://github.com/odoo/odoo/pull/127532

task-3389317

Part-of: odoo/odoo#138670
This commit is contained in:
Elisabeth Dickinson
2023-10-23 20:07:23 +00:00
committed by Leonardo Pavan Rocha
parent f9222c4976
commit 775ff75e40
6 changed files with 56 additions and 147 deletions
@@ -1,10 +1,7 @@
.o_calendar_filter {
span {
vertical-align: middle;
}
& img {
width:30px;
img:not(.o_avatar) {
width: 30px;
&.o_calendar_filter_plain {
content:var(--calendarFilter-icon--plain);
@@ -19,23 +16,6 @@
}
}
.o_timeoff_legend {
display: inline-block;
width: 24px;
height: 30px;
margin: 0 3px;
padding: 3px 0;
text-align: center;
&_bankholiday {
background-color: $gray-200;
}
&_mandatoryday {
font-weight: 600;
}
}
@for $size from 1 through length($o-colors) {
.hr_mandatory_day_#{$size - 1}:not(.fc-disabled-day) {
color: nth($o-colors, $size) !important;
@@ -3,12 +3,12 @@
<t t-name="hr_holidays.CalendarFilterPanel" t-inherit="web.CalendarFilterPanel" t-inherit-mode="primary">
<xpath expr="//t[@t-foreach='props.model.filterSections']" position="after">
<div class="o_calendar_filter">
<div class="o_calendar_filter mt-4">
<h5>Legend</h5>
<div class="d-flex flex-column">
<span><img class="o_calendar_filter_plain" src="/hr/static/src/img/icons/plain.svg"/> Validated</span>
<span><img class="o_calendar_filter_hatched" src="/hr/static/src/img/icons/hatched.svg"/> To Approve</span>
<span><img class="o_calendar_filter_line" src="/hr/static/src/img/icons/line.svg"/> Refused</span>
<span class="align-middle"><img class="o_calendar_filter_plain" src="/hr/static/src/img/icons/plain.svg"/> Validated</span>
<span class="align-middle"><img class="o_calendar_filter_hatched" src="/hr/static/src/img/icons/hatched.svg"/> To Approve</span>
<span class="align-middle"><img class="o_calendar_filter_line" src="/hr/static/src/img/icons/line.svg"/> Refused</span>
</div>
<div class="d-flex flex-column mt-4" t-if="leaveState.mandatoryDays.length">
@@ -40,7 +40,7 @@
<t t-name="hr_holidays.CalendarFilterPanel.filter" t-inherit="web.CalendarFilterPanel.filter" t-inherit-mode="primary">
<xpath expr="//span[@t-esc='filter.label']" position="replace">
<span class="o_cw_filter_title text-truncate flex-grow">
<span class="o_cw_filter_title flex-grow-1 text-truncate lh-base">
<t t-esc="filter.label"/>
<t t-if="env.isSmall">
@@ -28,6 +28,9 @@ $o-cw-filter-avatar-size: 20px;
}
.o_calendar_sidebar_container {
--Avatar-size: #{$o-cw-filter-avatar-size};
flex: 0 0 auto;
position: relative;
grid-area: side;
background-color: $o-view-background-color;
@@ -59,82 +62,17 @@ $o-cw-filter-avatar-size: 20px;
}
.o_calendar_filter {
font-size: 0.9em;
padding: 2em 0 1em;
.o_cw_filter_collapse_icon {
transition: all 0.3s ease;
@include o-hover-opacity();
font-size: 0.7em;
}
.collapsed .o_cw_filter_collapse_icon {
transform: rotate(90deg);
opacity: 1;
}
.o_calendar_filter_items_checkall,
.o_calendar_filter_item {
cursor: pointer;
overflow: hidden;
input {
z-index: -1;
opacity: 0;
}
.o_cw_filter_input_bg {
width: 1.3em;
height: 1.3em;
border-width: 2px;
border-style: solid;
border-radius: 1px;
overflow: hidden;
display: flex;
&.o_beside_avatar {
width: $o-cw-filter-avatar-size;
height: $o-cw-filter-avatar-size;
border-radius: 2px;
object-fit: cover;
align-items: center;
}
}
input:not(:checked) + label .o_cw_filter_input_bg {
&:not(.o_cw_filter_avatar) {
background: transparent !important;
}
i.fa {
visibility: hidden;
}
}
.o_cw_filter_avatar {
width: $o-cw-filter-avatar-size;
height: $o-cw-filter-avatar-size;
border-radius: 2px;
&.fa {
padding: 4px 3px;
}
}
.o_cw_filter_title {
line-height: $o-line-height-base;
flex-grow: 1;
}
button.o_remove {
@include o-position-absolute(0, 0, 0);
transform: translateX(100%);
transition: transform 0.2s;
transform: translate(100%, -50%);
}
&:hover {
button.o_remove {
transform: translateX(0%);
transform: translate(0%, -50%);
}
}
}
@@ -573,10 +573,16 @@
}
.o_cw_filter_color_#{$i - 1} {
.o_cw_filter_input_bg:not(.no_filter_color) {
&.form-check:hover .o_cw_filter_input_bg:not(.no_filter_color) {
border-color: shade-color($color, 20%);
}
.o_cw_filter_input_bg {
border-color: $color;
background: $color;
color: color-contrast($color);
&:checked {
background-color: $color;
}
}
}
@@ -7,7 +7,7 @@
overflow: hidden !important;
}
&.o-section-slide-enter-active {
max-height: 20rem; // fixed value is required to properly trigger transition
max-height: 100%; // max-height is required to properly trigger transition
overflow: auto;
}
.o_calendar_filter_item {
@@ -5,63 +5,52 @@
<t t-foreach="props.model.filterSections" t-as="section" t-key="section.fieldName">
<t t-if="section.filters.length gt 0">
<div
class="o_calendar_filter"
class="o_calendar_filter d-flex flex-column gap-1 mt-4"
t-att-class="{'o-calendar-filter-panel--section-collapsed': isSectionCollapsed(section)}"
t-att-data-name="section.fieldName"
>
<t t-if="section.label">
<div class="d-flex">
<div
class="o_calendar_filter_items_checkall me-2"
data-value="section"
>
<t t-set="filterId" t-value="nextFilterId" />
<input
type="checkbox"
name="select-all"
class="position-absolute"
t-attf-id="o_calendar_filter_{{filterId}}"
t-att-checked="isAllActive(section)"
t-on-change="(ev) => this.onAllFilterInputChange(section, ev)"
/>
<div
class="o_calendar_filter_items_checkall o-checkbox form-check"
data-value="section"
>
<t t-set="filterId" t-value="nextFilterId"/>
<input
type="checkbox"
name="select-all"
class="form-check-input"
t-attf-id="o_calendar_filter_{{filterId}}"
t-att-checked="isAllActive(section)"
t-on-change="(ev) => this.onAllFilterInputChange(section, ev)"
/>
<t t-if="section.canCollapse">
<label
class="d-flex align-items-center m-0"
t-attf-for="o_calendar_filter_{{filterId}}"
>
<span class="o_cw_filter_input_bg o_calendar_filter_all">
<i class="fa fa-check position-relative" />
</span>
</label>
</div>
<t t-if="section.canCollapse">
<div
class="justify-content-between align-items-center h5"
class="d-flex align-items-center"
type="button"
t-on-click.stop.prevent="() => this.toggleSection(section, ev)"
>
<span class="o_cw_filter_label" t-esc="section.label" />
<span class="o_cw_filter_label fw-bolder" t-esc="section.label"/>
<i
class="o_cw_filter_collapse_icon fa"
t-attf-class="fa-chevron-{{ isSectionCollapsed(section) ? 'left' : 'down' }}"
class="o_cw_filter_collapse_icon fa ms-1"
t-attf-class="fa-caret-{{ isSectionCollapsed(section) ? 'left' : 'down' }}"
/>
</div>
</label>
</t>
<t t-else="">
<h5 class="o_cw_filter_label" t-esc="section.label" />
<label class="o_cw_filter_label fw-bolder" t-esc="section.label"/>
</t>
</div>
</t>
<Transition visible="!isSectionCollapsed(section)" name="'o-section-slide'" leaveDuration="350" t-slot-scope="transition">
<div class="o_calendar_filter_items" t-att-class="transition.className">
<div class="o_calendar_filter_items d-flex flex-column gap-1" t-att-class="transition.className">
<t t-foreach="getSortedFilters(section)" t-as="filter" t-key="filter.value">
<t t-set="filterId" t-value="nextFilterId" />
<t t-call="{{ constructor.subTemplates.filter }}" />
<t t-set="filterId" t-value="nextFilterId"/>
<t t-call="{{ constructor.subTemplates.filter }}"/>
</t>
</div>
</Transition>
<t t-if="section.canAddFilter">
<AutoComplete t-props="getAutoCompleteProps(section)" />
<AutoComplete t-props="getAutoCompleteProps(section)"/>
</t>
</div>
</t>
@@ -70,56 +59,52 @@
<t t-name="web.CalendarFilterPanel.filter">
<div
class="o_calendar_filter_item w-100 position-relative mb-2"
class="o_calendar_filter_item o-checkbox form-check position-relative w-100 overflow-hidden cursor-pointer"
t-att-class="getFilterColor(filter)"
t-att-data-value="filter.value"
>
<input
type="checkbox"
name="selection"
class="position-absolute"
class="o_cw_filter_input_bg form-check-input"
t-att-style="filter.colorIndex and typeof filter.colorIndex !== 'number' ? `border-color: ${filter.colorIndex}; background-color: ${filter.colorIndex};` : ''"
t-attf-id="o_calendar_filter_item_{{filterId}}"
t-att-checked="filter.active"
t-on-change="(ev) => this.onFilterInputChange(section, filter, ev)"
/>
<label
class="d-flex align-items-start m-0"
class="d-flex align-items-center gap-1"
t-attf-for="o_calendar_filter_item_{{filterId}}"
>
<span
class="o_cw_filter_input_bg d-flex flex-shrink-0 justify-content-center position-relative me-1 o_beside_avatar"
>
<i class="fa fa-check position-relative" />
</span>
<t t-if="section.hasAvatar and filter.hasAvatar">
<img
class="o_cw_filter_avatar flex-shrink-0 me-1"
class="o_cw_filter_avatar o_avatar rounded"
t-attf-src="/web/image/{{ section.avatar.model }}/{{ filter.value }}/{{ section.avatar.field }}"
alt="Avatar"
/>
</t>
<t t-elif="filter.type === 'all'">
<i
class="o_cw_filter_avatar fa fa-users fa-fw flex-shrink-0 me-1"
class="o_cw_filter_avatar o_avatar fa fa-users fa-fw flex-shrink-0 me-1"
role="img"
aria-label="Avatar"
title="Avatar"
/>
</t>
<span
class="o_cw_filter_title text-truncate flex-grow"
class="o_cw_filter_title flex-grow-1 text-truncate lh-base"
t-esc="filter.label"
/>
</label>
<t t-if="filter.canRemove">
<button
class="o_remove btn bg-white text-700 py-0 px-2"
class="o_remove btn position-absolute top-50 end-0 bg-white py-0 px-2 text-700 transition-base"
role="img"
title="Remove this favorite from the list"
aria-label="Remove this favorite from the list"
t-on-click="() => this.onFilterRemoveBtnClick(section, filter)"
>
<i class="fa fa-times" />
<i class="oi oi-close"/>
</button>
</t>
</div>