[IMP] calendar,hr_holidays, web: global revamp of the calendar view

What's new:
- The overall style is softer, the borders lighter
- The event's colors are less bright
- In month view: The AllDay events and multiple day events are block
colors while the events with start/end times on a single day have a
colored circle.
- A header hosts the date title and navigation buttons (which were in
the sidebar)
- The sidebar is narrower and collapses

We've fixed the height issues giving us double scrollbars in some views.
The sidebar, when long, was pushing the content beyond the frame giving 
us extra scrollbars. This has been fixed with a CSS grid and 
`overflow-y` on the proper elements.

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 2bc3d44b8b
commit f9222c4976
22 changed files with 490 additions and 550 deletions
+73 -76
View File
@@ -1,13 +1,11 @@
.o_cw_popover .o_cw_popover_fields_secondary {
max-height: 75vh;
& > li > div {
min-width: 0;
}
}
.o_cw_body {
max-width: 328px;
}
.o_cw_body .o_field_copy {
max-width: calc(100% - 6rem);
@@ -18,95 +16,94 @@
padding-top: 0px !important;
}
.o_field_many2manyattendee .o_field_tags {
.o_field_many2manyattendeeexpandable .o_field_tags {
flex-direction: column;
span.badge {
width: fit-content;
}
.o_field_many2many_selection {
flex: 1 0 auto;
}
}
.o_cw_popover_link {
&.o_attendee_status_needsAction {
background-color: rgba($o-view-background-color, 0.9) !important;
}
@for $-i from 1 through length($o-colors-complete) {
$-color: nth($o-colors-complete, $-i);
$-color-subtle: mix($o-white, $-color, 85%);
&.o_attendee_status_declined {
text-decoration: line-through;
background-color: rgba($o-view-background-color, 0.9) !important;
}
}
.o_calendar_renderer .fc-event.o_calendar_color_#{$-i - 1} {
&:not(.o_event_dot) {
--o-overlay-opacity: .5;
.o_calendar_renderer {
.fc-event {
&.o_attendee_status_needsAction,
&.o_attendee_status_tentative,
&.o_attendee_status_declined,
&.o_attendee_status_alone {
border-width: 2px !important;
}
&.o_attendee_status_alone,
&.o_attendee_status_needsAction {
background-color: rgba($o-view-background-color, 0.9) !important;
color: $o-black !important;
.fc-bg {
background-color: rgba($o-view-background-color, 0.9) !important;
}
}
&.o_attendee_status_declined {
text-decoration: line-through;
background-color: rgba($o-view-background-color, 0.9) !important;
color: $o-black !important;
.fc-bg {
background-color: rgba($o-view-background-color, 0.9) !important;
}
}
}
}
@for $i from 1 through length($o-colors-complete) {
$color: nth($o-colors-complete, $i);
.o_cw_popover_link.o_calendar_color_#{$i - 1} {
&.o_attendee_status_tentative {
color: color-contrast($color);
background: repeating-linear-gradient(
45deg,
$color,
$color 10px,
rgba($color, 0.7) 10px,
rgba($color, 0.7) 20px
) !important;
}
}
.o_calendar_renderer {
.fc-event.o_calendar_color_#{$i - 1} {
&.o_attendee_status_needsAction,
&.o_attendee_status_tentative,
&.o_attendee_status_declined,
&.o_attendee_status_alone {
&.o_cw_custom_highlight {
background-color: $color;
}
&.o_attendee_status_active {
--o-bg-opacity: 1;
}
&.o_attendee_status_tentative {
color: color-contrast($color) !important;
&.o_attendee_status_tentative, &.o_event_hatched {
--o-bg-opacity: .5;
.fc-bg {
background: repeating-linear-gradient(
45deg,
$color,
$color 10px,
rgba(white, 0.4) 10px,
rgba(white, 0.4) 20px
rgba($-color, .3),
rgba($-color, .3) 10px,
rgba($-color, .6) 10px,
rgba($-color, .6) 20px
) !important;
}
}
&.o_attendee_status_alone,
&.o_attendee_status_needsAction {
--o-bg-opacity: .5;
}
&.o_attendee_status_declined {
--o-bg-opacity: 0;
}
}
&.o_event_dot {
--o-overlay-opacity: .25;
display: flex;
align-items: center;
gap: map-get($spacers, 1 );
border: none;
background-color: rgba($-color-subtle, var(--o-bg-opacity));
&:before {
content:'\f111'; // fa-circle
display: inline-block;
z-index: 2;
font-family: Fontawesome;
color: $-color;
}
&.o_attendee_status_needsAction, &.o_event_hatched {
&:before {
content: "\f1db"; // fa-circle-thin
}
}
&.o_attendee_status_tentative:before {
content: "\f059"; // fa-question-circle
}
&.o_attendee_status_declined:before {
content: "\f05e"; // fa-ban
}
&.o_attendee_status_alone {
content: "\f06a"; // fa-exclamation-circle
}
&:hover {
--o-bg-opacity: 1;
}
}
&.o_attendee_status_declined, &.o_event_striked {
.fc-content {
text-decoration: line-through;
}
}
}
}
@@ -1,19 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-name="calendar.AttendeeCalendarCommonRenderer.event">
<div class="fc-content">
<div t-attf-class="#{attendeeStatus != 'accepted' ? 'fw-normal' : ''} o_event_title me-2">
<span t-if="isAlone" class="fa fa-exclamation-circle"/>
<t t-esc="title"/>
<t t-if="!isAllDay">
<t t-if="24 > duration and duration > 0.5">
<br/>
<span class="fw-normal"><t t-esc="startTime" /> - <t t-esc="endTime" /></span>
<div class="fc-content" t-att-class="isMonth ? 'd-flex gap-1 text-truncate' : ''">
<span t-if="!isTimeHidden and isMonth" class="d-none d-lg-inline fc-time fw-normal" t-esc="startTime" />
<div t-attf-class="o_event_title text-truncate">
<i t-if="isAlone" class="fa fa-exclamation-circle align-self-top me-1" data-tooltip="You're alone in this meeting"/>
<span t-esc="title" t-attf-class="#{(attendeeStatus == 'accepted' || rawRecord.is_highlighted) ? 'fw-bolder' : ''} text-truncate"/>
<t t-if="!isAllDay and !isMonth">
<t t-if="24 > duration and duration > 0.5">
<br/><span class="fw-normal mt-1"><t t-esc="startTime"/> - <t t-esc="endTime"/></span>
</t>
<t t-else="">
, <t t-esc="startTime"/>
</t>
</t>
<t t-else="">, <t t-esc="startTime"/></t>
</t>
</div>
<span t-if="!isTimeHidden" class="fc-time" t-esc="startTime" />
<span t-if="!isTimeHidden and !isMonth" class="fc-time" t-esc="startTime" />
</div>
</t>
</templates>
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="calendar.CalendarQuickCreateButtons" t-inherit="web.FormViewDialog.ToOne.buttons">
<xpath expr="//button[contains(@class, 'o_form_button_cancel')]" position="after">
<button class="btn btn-secondary ms-auto" t-on-click="goToFullEvent">More Options</button>
<button class="btn btn-link ms-auto" t-on-click="goToFullEvent">More Options</button>
</xpath>
</t>
</templates>
@@ -3,7 +3,7 @@
<t t-name="calendar.WeekDays">
<div class="o_recurrent_weekdays mb-2 d-flex">
<t t-foreach="weekdays" t-as="day" t-key="day">
<div t-attf-class="o_calendar_week_days_rounded {{data[day] ? 'btn-primary' : 'btn-secondary'}}" t-on-click="() => this.onChange(day)">
<div t-attf-class="o_calendar_week_days_rounded {{data[day] ? 'text-bg-action' : 'btn-secondary'}}" t-on-click="() => this.onChange(day)">
<t t-esc="props.record.fields[day].string[0]"/>
</div>
</t>
@@ -4,10 +4,7 @@
justify-content: start;
flex: 1;
text-align: center;
&:not(:last-child) {
border-right: 2px solid $border-color;
}
border-right: 1px solid $border-color;
&>* {
width: fit-content;
@@ -1,7 +1,9 @@
.o_timeoff_calendar {
.o_calendar_renderer {
height: unset;
background-color: $o-view-background-color;
flex-grow: 1;
flex-basis: fit-content;
.o_calendar_renderer {
@for $size from 1 through length($o-colors) {
.o_calendar_widget {
.hr_mandatory_day_top_#{$size - 1}:not(.fc-disabled-day) {
@@ -1,14 +0,0 @@
.o_timeoff_calendar {
.o_calendar_widget {
.fc-dayGridYear-view {
.fc-week-number {
color: #adb5bd;
font-size: 0.85rem;
cursor: default;
vertical-align: middle;
line-height: unset;
}
}
}
}
@@ -67,7 +67,7 @@ export class CalendarCommonRenderer extends Component {
get options() {
return {
allDaySlot: this.props.model.hasAllDaySlot,
allDayText: _t("All day"),
allDayText: _t(""),
columnHeaderFormat: this.env.isSmall
? SHORT_SCALE_TO_HEADER_FORMAT[this.props.model.scale]
: SCALE_TO_HEADER_FORMAT[this.props.model.scale],
@@ -217,7 +217,6 @@ export class CalendarCommonRenderer extends Component {
onEventRender(info) {
const { el, event } = info;
el.dataset.eventId = event.id;
el.classList.add("o_event", "py-0");
const record = this.props.model.records[event.id];
if (record) {
@@ -252,12 +251,18 @@ export class CalendarCommonRenderer extends Component {
if (DateTime.now() >= record.end) {
el.classList.add("o_past_event");
}
}
if (!el.querySelector(".fc-bg")) {
const bg = document.createElement("div");
bg.classList.add("fc-bg");
el.appendChild(bg);
if (!record.isAllDay && !record.isTimeHidden && record.isMonth) {
el.classList.add("o_event_dot");
} else if (record.isAllDay) {
el.classList.add("o_event_allday");
}
if (!el.classList.contains("fc-bg")) {
const bg = document.createElement("div");
bg.classList.add("fc-bg");
el.appendChild(bg);
}
}
}
async onSelect(info) {
@@ -6,12 +6,12 @@
</t>
<t t-name="web.CalendarCommonRenderer.event">
<div class="fc-content">
<div class="fc-content" t-att-class="isMonth ? 'd-flex gap-1 text-truncate' : ''">
<t t-if="!isTimeHidden">
<span class="fc-time" t-esc="startTime" />
<span class="d-none d-lg-inline fc-time" t-esc="startTime" />
<t> </t>
</t>
<div class="o_event_title" t-esc="title"/>
<div class="o_event_title text-truncate" t-out="title"/>
</div>
</t>
@@ -1,5 +1,5 @@
// Variables
$o-cw-color-today-accent: #fe3b30;
$o-cw-color-today-accent: #714B67;
$o-cw-filter-avatar-size: 20px;
// Animations
@@ -13,23 +13,31 @@ $o-cw-filter-avatar-size: 20px;
}
.o_calendar_container {
height: 100%;
display: flex;
grid-template-columns: auto minmax(auto, 210px);
@include media-breakpoint-up(xl){
grid-template: auto 1fr / 1fr auto;
grid-template-areas:
"head head"
"cal side";
}
.o_calendar_header {
grid-area: head;
}
}
.o_calendar_sidebar_container {
flex: 0 0 auto;
position: relative;
@include o-webclient-padding($top: $o-horizontal-padding/2);
grid-area: side;
background-color: $o-view-background-color;
border-right: 1px solid $border-color;
overflow-y: auto;
width: 240px;
@include media-breakpoint-up(xl){
width: 280px;
}
.o_calendar_sidebar {
@include o-webclient-padding($top: $o-horizontal-padding/2);
@include media-breakpoint-up(xl){
width: 210px;
}
.o_datetime_picker {
--DateTimePicker__Cell-size-md: 1.8rem;
@include media-breakpoint-up(xl){
@@ -13,44 +13,45 @@
<t t-set-slot="layout-actions">
<SearchBar t-if="searchBarToggler.state.showSearchBar"/>
</t>
<t t-set-slot="control-panel-additional-breadcrums">
<span class="currentDate"><t t-out="currentDate"/></span>
</t>
<t t-set-slot="control-panel-navigation-additional">
<t t-component="searchBarToggler.component" t-props="searchBarToggler.props"/>
</t>
<div class="o_calendar_container">
<MobileFilterPanel t-if="env.isSmall" t-props="mobileFilterPanelProps" />
<div t-if="showSideBar" class="o_calendar_sidebar_container d-md-block">
<div class="d-flex justify-content-between">
<div class="o_calendar_container d-flex d-lg-grid flex-column h-100 bg-view">
<div class="o_calendar_header d-flex align-items-center gap-1 p-2 border-bottom">
<div class="o_calendar_navigation_buttons btn-group">
<button
class="btn btn-secondary me-1 o_calendar_button_today"
t-on-click.stop="() => this.setDate('today')"
>
Today
</button>
<div class="o_calendar_navigation_buttons btn-group">
<button
class="o_calendar_button_prev btn btn-secondary btn-sm d-none d-md-block"
title="Previous"
aria-label="Previous"
t-on-click.stop="() => this.setDate('previous')"
><i class="oi oi-arrow-left"/></button>
<ViewScaleSelector scales="scales" currentScale="model.scale" isWeekendVisible="state.isWeekendVisible" setScale.bind="setScale" toggleWeekendVisibility.bind="toggleWeekendVisibility" />
<button
class="o_calendar_button_next btn btn-secondary btn-sm d-none d-md-block"
title="Next"
aria-label="Next"
t-on-click.stop="() => this.setDate('next')"
><i class="oi oi-arrow-right"/></button>
</div>
class="o_calendar_button_prev btn btn-secondary d-none d-md-block"
title="Previous"
aria-label="Previous"
t-on-click.stop="() => this.setDate('previous')"
><i class="oi oi-arrow-left"/></button>
<button
class="o_calendar_button_next btn btn-secondary d-none d-md-block"
title="Next"
aria-label="Next"
t-on-click.stop="() => this.setDate('next')"
><i class="oi oi-arrow-right"/></button>
</div>
<ViewScaleSelector scales="scales" currentScale="model.scale" isWeekendVisible="weekends" setScale.bind="setScale"/>
<button
class="btn btn-secondary o_calendar_button_today order-3 order-lg-0"
t-att-class="env.isSmall ? 'btn-sm btn-light' : 'btn-secondary'"
t-on-click.stop="() => this.setDate('today')"
> <span t-if="env.isSmall" class="position-relative pt-1"><t t-esc="today"/><i class="fa fa-calendar-o position-absolute top-50 start-50 translate-middle fs-1"></i></span>
<t t-else="">Today</t>
</button>
<!-- [TODO] -->
<h5 class="d-inline-flex mb-0">October 2023 <span class="badge bg-100 rounded px-1 ms-1">Week 40</span></h5>
<button class="btn btn-light d-none d-lg-block oi oi-panel-right ms-auto collapsed" data-bs-target=".o_calendar_sidebar_container" data-bs-toggle="collapse" aria-expanded="true"/>
</div>
<MobileFilterPanel t-if="env.isSmall" t-props="mobileFilterPanelProps" />
<t t-if="showCalendar" t-component="props.Renderer" t-props="rendererProps" />
<div t-if="showSideBar" class="o_calendar_sidebar_container col-auto collapse-horizontal collapse show overflow-x-hidden overflow-y-auto">
<div class="o_calendar_sidebar">
<DatePicker t-if="!env.isSmall" t-props="datePickerProps" />
<FilterPanel t-props="filterPanelProps" />
</div>
</div>
<t t-if="showCalendar" t-component="props.Renderer" t-props="rendererProps" />
</div>
</Layout>
</div>
@@ -10,8 +10,6 @@
}
.o_calendar_container {
flex-direction: column;
.o_other_calendar_panel {
padding: 8px 16px;
@@ -38,7 +36,7 @@
}
.o_calendar_sidebar_container {
flex-grow: 1;
height: 100%;
> .o_calendar_sidebar {
width: auto;
@@ -549,6 +549,7 @@ export class CalendarModel extends Model {
isHatched: rawRecord["is_hatched"] || false,
isStriked: rawRecord["is_striked"] || false,
isTimeHidden: isTimeHidden || !showTime,
isMonth: this.meta.scale === "month",
rawRecord,
};
}
@@ -1,94 +1,86 @@
.o_calendar_renderer {
--o-circle-padding: calc(#{map-get($spacers, 1 )} / 2);
flex: 1 1 auto;
min-width: 0;
height: 100%;
background-color: map-get($grays, "100");
background: linear-gradient(-45deg, map-get($grays, "100"), $o-view-background-color);
--o-cw-border-color: #{lighten($border-color, 5%)};
background-color: $o-view-background-color;
grid-area: cal;
@include media-breakpoint-down(lg) {
border-top: 1px solid var(--o-cw-border-color);
}
.fc-event {
margin: 0 1px;
border-style: solid;
border-width: 0 0 0 3px;
box-sizing: border-box;
overflow: hidden;
background: none;
font-size: 11px;
line-height: 1;
// `web/lib/fullcalendar/core/main.css` gives events with links and draggable events a hand mouse pointer,
// but doesn't take into account that events have popovers.
cursor: pointer;
color: $body-color;
background-color: $o-view-background-color;
transition: right .3s, left .3s;
&:not([href]):not([tabindex]) {
&:hover {
color: $body-color;
&:not(.o_event_dot) .fc-bg {
--o-bg-opacity: .35;
}
}
&.fc-dragging.fc-day-grid-event.dayGridMonth .fc-content {
@include text-truncate();
margin: 4px 4px 3px;
&.fc-mirror, &.fc-dragging {
--o-bg-opacity: .25;
border-color: rgba($o-action, .5);
.fc-bg {
background-color: rgba($o-action, var(--o-bg-opacity));
}
}
&.fc-mirror {
background-color: rgba($o-action, var(--o-bg-opacity));
}
&.o_past_event::after{
content: '';
@include o-position-absolute(0, 0, 0, 0);
display: block;
z-index: 3;
background-color: rgba($o-view-background-color, var(--o-overlay-opacity));
}
.fc-bg {
background-color: mix(
map-get($theme-colors, "primary"),
white
); // Used for placeholder events only (on creation)
width: 101%;
height: 101%; // Compensate border
opacity: 0.7;
transition: opacity 0.2s;
transition: $transition-base;
}
.fc-content {
white-space: normal;
margin: 0.25rem;
font-size: 1.1em;
font-weight: 500;
}
// Try to show one full lien for short event
&.fc-short .fc-content {
margin-top: 1px;
}
&.o_cw_custom_highlight {
z-index: 10 !important;
.fc-bg {
opacity: 0.95;
}
margin: 0 map-get($spacers, 1);
}
}
.o_calendar_widget {
height: 100%;
> .fc-view-container {
height: 100%;
}
// === Adapt calendar table borders ===
// =====================================
.fc-row .fc-widget-header {
padding-top: map-get($spacers, 2);
}
td {
border-color: $border-color;
// === Adapt calendar table borders and general layout ===
// ========================================================
th, td {
border-color: var(--o-cw-border-color);
}
.fc-time-grid .fc-slats .fc-minor td {
border-top-color: map-get($grays, "400");
border-top-color: var(--o-cw-border-color);
}
.fc-widget-content {
border-left-color: transparent;
.fc-body > tr > .fc-widget-content {
border-top: 0;
}
.fc-widget-header {
border-color: transparent;
border-bottom-color: $border-color;
padding: 3px 0 5px;
// The left padding must be equal to that of '.fc-axis.fc-time'
// This realigns the headers with their cells
.fc-week-number {
padding-left: 4px;
}
.fc-widget-content, .fc-widget-header {
border-bottom: 0;
}
hr.fc-widget-header {
@@ -97,12 +89,24 @@
background: map-get($grays, "400");
}
.fc-timeGrid-view .fc-day-grid .fc-row .fc-content-skeleton {
padding: 0.5em;
}
.fc-head-container {
position: sticky;
top: 0;
z-index: $zindex-modal;
border-top: 0;
background-color: $o-view-background-color;
.fc-event-container {
color: white;
.fc-week-number {
text-align: center;
font-size: $o-font-size-base-smaller;
> span {
display: none;
padding: map-get($spacers,1);
border-radius: $border-radius;
background-color: rgba($gray-200, .5);
}
}
}
.fc-more-popover {
@@ -120,44 +124,112 @@
}
.o_calendar_disabled {
background-color: $gray-200;
background-color: rgba($gray-200, .5);
}
// ====== Specific agenda types ======
// ====================================
// ====== Day only
.fc-timeGridDay-view {
.fc-day-header {
text-align: left;
border: 0;
> span {
gap: map-get($spacers, 1);
margin-bottom: map-get($spacers, 1);
}
.o_cw_day_number {
padding: map-get($spacers, 1);
}
}
}
// ====== Week only
.fc-timeGridWeek-view {
.fc-day-header {
text-align: center;
> span{
flex-direction: column;
}
.o_cw_day_number {
padding: map-get($spacers, 1) map-get($spacers, 2);
@include media-breakpoint-up(lg) {
font-size: 1.25rem;
}
}
}
.fc-time-grid {
.fc-event-container {
margin: 1px;
}
}
}
// ====== Both Day and Week agenda
.fc-timeGridDay-view,
.fc-timeGridWeek-view {
.fc-axis {
padding-right: $o-horizontal-padding;
.fc-head-container {
border-bottom: 1px solid var(--o-cw-border-color);
}
.fc-day-header {
> span {
display: flex;
align-items: center;
margin-left: map-get($spacers, 1);
}
&.fc-today {
color: $primary;
.o_cw_day_number {
position:relative;
color: $o-view-background-color;
&:before {
content: '';
@include o-position-absolute($top: 50%, $left: 50%);
transform: translate(-50%,-50%);
z-index: -1;
width: 100%;
border-radius: $border-radius-pill;
background: $primary;
aspect-ratio: 1;
color: $o-view-background-color;
}
}
}
}
.fc-widget-header.fc-today {
border-radius: 25px;
background: $o-brand-odoo;
color: white;
}
// Reinfornce default border color
tbody td {
border-top-color: map-get($grays, "400");
}
// Remove dotted borders (half-hours)
.fc-time-grid .fc-slats .fc-minor td {
border-top-style: none;
}
// Align labels and timelines
.fc-axis.fc-time {
border-top-color: transparent;
// Remove dotted borders (half-hours)
span {
max-width: 45px;
margin-top: -19px;
position: relative;
display: block;
// Align labels and timelines
.fc-axis{
font-size: .6rem;
@include media-breakpoint-up(md) {
font-size: .75rem;
}
&.fc-time {
border-top-color: transparent;
span {
max-width: 7ch;
margin-top: -22px;
position: relative;
display: block;
}
}
}
@@ -170,9 +242,7 @@
// Row containing "all day" events
div.fc-day-grid {
background-color: $o-view-background-color;
box-shadow: 0 6px 12px -6px rgba(black, 0.16);
border-left-color: rgba($o-brand-odoo, 0.3);
border-right-color: rgba($o-brand-odoo, 0.3);
box-shadow: 0 6px 12px -6px rgba(0, 0, 0, 0.16);
+ hr.fc-widget-header {
padding: 1px 0 0;
@@ -184,41 +254,37 @@
}
}
// Create a 'preudo-border' for the first row. The actual border
// it's hidden because of border-collapse settings.
// Create a 'pseudo-border' for the first row. The actual border
// is hidden because of border-collapse settings.
.fc-slats tr:first-child td.fc-widget-content:last-child {
box-shadow: inset 0 1px 0 map-get($grays, "400");
box-shadow: inset 0 1px 0 var(--o-cw-border-color);
}
.fc-day.fc-widget-content.fc-today:not(.o_calendar_disabled) {
border-left-color: rgba($o-brand-odoo, 0.3);
border-right-color: rgba($o-brand-odoo, 0.3);
background: $o-view-background-color;
}
.fc-event {
--o-bg-opacity: .25;
// Prevent events with similar color to visually overlap each other
box-shadow: 0 0 0 1px white;
&.fc-event:not(.fc-h-event):not(.o_event_oneliner) {
border-width: 3px 0 0;
&.fc-not-start {
border-width: 0 0 3px;
&.fc-not-end {
border-width: 0;
}
}
&:not(.o_event_allday):not(.o_homework_event) {
box-shadow: 0 0 0 1px $o-view-background-color;
}
&.o_event_oneliner {
padding-top: 0;
padding-bottom: 0;
.fc-content {
&.o_cw_custom_highlight:not(.fc-dragging), &.o_calendar_popover_open:not(.fc-dragging) {
z-index: $zindex-modal !important;
right: 0px !important;
left: 0px !important;
margin-right: 0 !important;
}
.fc-content {
margin: map-get($spacers, 1);
@include media-breakpoint-up(md) {
margin-top: 0;
font-size: 11px !important;
line-height: 0.9;
margin-bottom: 0;
}
}
}
@@ -229,190 +295,124 @@
}
}
// ====== Both Month and Year agenda
// ====== Both Week and Month agenda
.fc-dayGridYear-view, .fc-dayGridMonth-view {
.fc-timeGridWeek-view, .fc-dayGridMonth-view {
.fc-day-header > span{
text-transform: uppercase;
font-size: $o-font-size-base-smaller;
}
}
// ====== Both Month and Months in Year agenda
.fc-dayGridMonth-view {
.fc-content-skeleton {
--o-cw-circle-padding: calc(#{map-get($spacers, 1 )} / 2);
--o-cw-color: var(--body-color);
// Realigns the background color and the number
height: 100%;
padding-bottom: 0;
.fc-day-number {
position: relative;
padding: var(--o-circle-padding);
color: var(--o-cw-color);
.fc-week-number {
line-height: $line-height-sm;
font-size: $o-font-size-base-smaller;
opacity: .8;
&:before {
content:"";
z-index: -1;
@include o_position-absolute($top: calc(#{var(--o-circle-padding)} * -1), $left: 50%);
transform: translateX(-50%);
display: none;
aspect-ratio: 1/1;
height: 100%;
border-radius: 100%;
background: var(--o-cw-bg, none);
padding: var(--o-circle-padding);
@include media-breakpoint-down(lg) {
> span {
font-size: .5rem;
}
}
@include media-breakpoint-up(lg) {
padding: map-get($spacers, 1);
}
}
.fc-today {
--o-cw-color: #{$white};
--o-cw-bg: #{$o-cw-color-today-accent};
.fc-day-top {
text-align: center;
.fc-day-number:before {
display: block;
&.fc-other-month {
opacity: 0.8;
&:not(.fc-today) .fc-day-number {
color: map-get($grays, "500");
}
}
.fc-day-number {
position: relative;
float: none !important;
color: var(--o-cw-color);
&:before {
content:"";
z-index: -1;
@include o_position-absolute($top: calc(#{var(--o-circle-padding)} * -1), $left: 50%);
transform: translateX(-50%);
display: none;
aspect-ratio: 1/1;
height: 100%;
border-radius: 100%;
background: var(--o-cw-bg, none);
padding: var(--o-circle-padding);
}
}
.fc-week-number {
// only in Month view
@include o-position-absolute($top: 0, $left: 0);
@include media-breakpoint-down(lg) {
background-color: $gray-100;
}
}
&.fc-today {
--o-cw-color: #{$white};
--o-cw-bg: #{$o-cw-color-today-accent};
padding-top: map-get($spacers, 1)/2;
.fc-day-number:before {
display: block;
}
}
}
}
}
// ====== Day only
.fc-timeGridDay-view .fc-event {
padding: 10px;
font-size: 14px;
// Try to avoid showing no title for short event
&.fc-short {
padding-top: 0;
padding-bottom: 0;
td:first-child {
border-left: none;
}
.fc-content {
margin-top: 1px !important;
}
}
// ====== Week only
.fc-timeGridWeek-view {
// Expand tiny events on hover/select
.fc-event:not(.fc-h-event).o_cw_custom_highlight {
transition: margin 0.1s 0.3s, left 0.1s 0.3s, right 0.1s 0.3s;
margin: 0 !important;
right: 1px !important;
left: 1px !important;
}
}
// ====== Month only
.fc-dayGridMonth-view {
margin-right: $o-horizontal-padding;
border-right: 1px solid $border-color;
.fc-event {
border-radius: 25px;
}
.fc-widget-header {
padding: 3px 0;
}
.fc-week-number {
background: none;
padding: 0.1rem 0.3rem 0.1rem 0 !important;
line-height: 1;
}
.fc-day-top {
text-align: center;
padding-top: 3px;
padding-bottom: 3px;
.fc-day-number {
float: none !important;
}
}
.fc-day-number {
margin: 5px;
padding: 0.1rem 0.3rem 0.1rem 0;
color: map-get($grays, "900");
font-weight: 400;
line-height: 1;
float: none !important;
}
.fc-day-top.fc-other-month {
opacity: 0.8;
.fc-day-number {
color: map-get($grays, "500");
}
}
td:last-child {
border-right-color: transparent;
}
.fc-bg .fc-today {
border-color: map-get($grays, "300");
}
.fc-bg .fc-today:not(.o_calendar_disabled) {
background: $o-view-background-color;
background: none;
}
.fc-more-cell {
> div,
.fc-more {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
}
.fc-event {
margin: 0 3px 2px;
@include media-breakpoint-up(lg) {
margin: 0 3px 2px;
}
.fc-content {
display: flex;
justify-content: start;
flex-direction: row;
margin: 4px 4px 3px;
}
.fc-time:not(:empty) {
/*rtl:ignore*/
padding-right: 0.5em;
}
.o_event_title {
@include text-truncate();
}
&.fc-not-start {
border-right-width: 3px;
.fc-content {
padding-left: 6px;
}
}
&.fc-not-end {
margin-right: 0;
.fc-content {
padding-right: 6px;
}
max-height: 1.2em;
}
}
}
// ====== Year only
.fc-dayGridYear-view {
border: none;
height: 100%;
padding-right: $o-horizontal-padding;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
overflow-y: auto;
@include media-breakpoint-down(md) {
padding-right: 5px;
padding-left: 5px;
}
> table {
height: 100%;
}
@@ -431,27 +431,25 @@
}
&:not(.fc-readonly-year-view) {
.fc-day-top:hover > .fc-day-number {
--o-cw-color: #{map-get($grays, "900")};
--o-cw-bg: #{rgba(#87c0d1, 0.5)};
.fc-day-top {
&.fc-today {
padding-top: 0;
}
position: relative;
font-weight: bold;
text-align: center;
&:hover > .fc-day-number {
--o-cw-color: #{$o-white};
--o-cw-bg: #{mix($o-white, $o-action, 50%)};
&:before {
display: block;
&:before {
display: block;
}
}
}
}
> .fc-month-container {
width: 25%;
min-width: 25rem;
box-sizing: border-box;
@include media-breakpoint-down(md) {
width: 50%;
width: 100%;
}
> .fc-month {
@@ -463,34 +461,50 @@
}
> .fc-toolbar.fc-header-toolbar {
padding-top: 10px;
margin-bottom: 4px;
cursor: default;
justify-content: start;
h2 {
font-size: 1.2rem;
color: map-get($grays, "600");
font-size: $font-size-base;
}
}
.fc-widget-header {
padding: 2px 0;
position: static;
cursor: default;
}
.fc-dayGridMonth-view {
margin-right: none;
border-right: none;
.fc-has-event {
background-color: #b4dff5;
}
.fc-week-number {
cursor: default;
opacity: .5;
}
.fc-day-header {
font-size: $o-font-size-base-smaller;
}
}
.fc-week.fc-row {
display: flex;
align-items: center;
min-height: 2rem;
.fc-week-number {
padding: 0;
> span {
padding: 0;
vertical-align: middle;
}
}
}
.fc-disabled-day {
@@ -499,21 +513,7 @@
.fc-day-top {
text-align: center;
padding: 0.4vh;
cursor: pointer;
> .fc-day-number {
display: block;
float: unset;
line-height: unset;
margin: auto;
padding: 0.1rem 0;
font-size: calc(11px + 0.2vh);
}
&.fc-today > .fc-day-number {
font-weight: bold;
}
}
}
}
@@ -550,84 +550,24 @@
}
}
.o_calendar_renderer .fc-view {
.fc-bgevent {
opacity: 0.5;
}
.fc-event {
opacity: 1;
&.o_event_highlight {
opacity: 1;
.fc-content {
font-weight: bold;
}
}
&.o_cw_custom_highlight {
z-index: 10 !important;
opacity: 1;
right: 1px !important;
left: 1px !important;
margin-right: 0 !important;
}
}
}
.o_cw_popover {
.card-header {
padding-left: 2px;
}
}
// =============== Generate color classes ===============
@for $i from 1 through length($o-colors-complete) {
$color: nth($o-colors-complete, $i);
$color-subtle: mix($o-white, $color, 55%);
.o_calendar_renderer .fc-view {
.o_calendar_color_#{$i - 1} {
border-color: $color;
&.fc-bgevent {
background-color: $color;
&.fc-bgevent, &:not(.o_event_dot) .fc-bg {
background-color: $color-subtle;
}
&.fc-event {
color: darken($color, 45%);
background: scale-color($color, $lightness: 50%);
.fc-bg {
background: scale-color($color, $lightness: 50%);
&.fc-event:not(.o_event_dot):not(.fc-dragging) {
color: color-contrast($color-subtle);
border-color: tint-color($color, 50%);
&.o_cw_custom_highlight, &.o_calendar_popover_open {
box-shadow: 0px 8px 2px -7px rgba(0, 0, 0, 0.5);
z-index: 2; // for the shadow to go over the events below
}
&.o_cw_custom_highlight {
box-shadow: 0 12px 12px -5px rgba($color, 0.3);
color: color-contrast($color);
}
}
&.o_event_hatched {
background: repeating-linear-gradient(
45deg,
$color,
$color 10px,
rgba($color, 0.4) 10px,
rgba($color, 0.4) 20px
) !important;
.fc-bg {
background: repeating-linear-gradient(
45deg,
$color,
$color 10px,
rgba($color, 0.5) 10px,
rgba($color, 0.5) 20px
);
}
}
&.o_event_striked {
background: linear-gradient(
transparent 0 45%,
$color 45% 55%,
transparent 55% 100%);
}
}
}
@@ -650,6 +590,7 @@
}
.card-header {
padding-left: 2px;
border-color: mix($card-border-color, mix($o-white, $color));
}
}
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="web.CalendarRenderer">
<div class="o_calendar_renderer">
<div class="o_calendar_renderer h-100">
<ActionSwiper t-props="actionSwiperProps">
<t
t-component="calendarComponent"
@@ -6,23 +6,19 @@
.fc-axis {
padding-left: 0;
}
.fc-week-number.fc-widget-header {
font-weight: normal;
white-space: normal;
}
}
&:not(.fc-timeGridDay-view) {
.fc-day-header, .fc-week-number.fc-widget-header {
word-spacing: 250px; // force line break in week mode
text-align: center;
}
&.fc-timeGrid-view .fc-axis.fc-time span {
max-width: 5ch;
}
&.fc-dayGridMonth-view {
padding-left: 0;
.fc-week-number:not(.fc-widget-header) {
background-color: $gray-400;
color: $gray-800;
}
.fc-body > tr > .fc-widget-content {
border: 0
}
.fc-head-container.fc-widget-header {
border-left: 0;
border-right: 0;
}
}
@@ -56,7 +56,7 @@ export class CalendarYearRenderer extends Component {
selectable: this.props.model.canCreate,
showNonCurrentDates: false,
timeZone: luxon.Settings.defaultZone.name,
titleFormat: { month: "short", year: "numeric" },
titleFormat: { month: "long", year: "numeric" },
unselectAuto: false,
weekNumberCalculation: "ISO",
weekNumbers: false,
@@ -145,7 +145,6 @@ export class CalendarYearRenderer extends Component {
onEventRender(info) {
const { el, event } = info;
el.dataset.eventId = event.id;
el.classList.add("o_event");
const record = this.props.model.records[event.id];
if (record) {
const color = getColor(record.colorIndex);
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="web.CalendarYearRenderer">
<div class="o_calendar_widget" t-ref="root">
<div class="o_calendar_widget overflow-y-auto" t-ref="root">
<div class="fc-view-container">
<div class="fc fc-dayGridYear-view">
<t t-foreach="months" t-as="month" t-key="month">
@@ -10,4 +10,13 @@
max-height: 20rem; // fixed value is required to properly trigger transition
overflow: auto;
}
}
.o_calendar_filter_item {
&.no_filter_color, &.o_cw_filter_color_false, &:not([class*='o_cw_filter_color']) {
input, input:hover {
border-color: $light;
background-color: transparent !important;
filter: invert(1) grayscale(1);
}
}
}
}
@@ -3,22 +3,20 @@
<t t-name="web.CalendarMobileFilterPanel">
<div class="o_other_calendar_panel d-flex align-items-center" t-on-click="props.toggleSideBar">
<i class="fa fa-fw fa-filter me-3" />
<div class="o_filter me-auto d-flex overflow-auto">
<t t-foreach="props.model.filterSections" t-as="section" t-key="section.fieldName">
<t t-if="section.filters.length gt 0">
<span class="text-nowrap fw-bold text-uppercase me-1" t-esc="section.label" />
<t t-foreach="getSortedFilters(section)" t-as="filter" t-key="filter.value">
<span t-if="filter.active" class="d-flex align-items-center text-nowrap ms-1 me-2">
<span t-att-class="getFilterColor(filter)">⬤</span>
<i class="fa fa-fw" t-att-class="getFilterColor(filter) !== 'o_color_false' ? 'fa-circle ' + getFilterColor(filter) : 'fa-circle-o'"/>
<span class="ms-1 fw-bold text-nowrap" t-esc="filter.label" />
</span>
</t>
</t>
</t>
</div>
<i t-attf-class="fa fa-fw fa-caret-{{caretDirection}} ms-2" />
<i t-attf-class="oi fa-fw oi-chevron-{{caretDirection}} ms-2" />
</div>
</t>
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="web.ViewScaleSelector">
<Dropdown t-if="Object.keys(props.scales).length > 1" class="'btn-group o_view_scale_selector'" togglerClass="'btn btn-secondary scale_button_selection'" hotkey="'v'" showCaret="true">
<Dropdown t-if="Object.keys(props.scales).length > 1" class="'btn-group o_view_scale_selector order-2 order-lg-0 ms-auto ms-lg-0'" togglerClass="'btn btn-secondary scale_button_selection'" hotkey="'v'" showCaret="true">
<t t-set-slot="toggler">
<t t-esc="props.scales[props.currentScale].description" />
</t>
@@ -298,7 +298,7 @@ export function findDateCell(target, date) {
}
export function findEvent(target, eventId) {
return target.querySelector(`.o_event[data-event-id="${eventId}"]`);
return target.querySelector(`.fc_event[data-event-id="${eventId}"]`);
}
function findDateCol(target, date) {