fix: улучшить стили многодневных событий календаря

Проблемы:
- Многодневные события неправильно растягивались
- Инлайн-стили JS перезаписывали SCSS правила
- Не было четкой визуализации начала/конца/середины события

Решение:

1. Обновлён eventDidMount в calendarWidget.js:
   - Убраны инлайн-стили для border-radius, padding, box-shadow
   - Добавлен атрибут data-has-calendar-color для SCSS селекторов
   - Упрощена логика - доверяем SCSS стилям
   - Определение многодневных событий через info.isStart/isEnd

2. Улучшены SCSS стили в _calendar-events.scss:
   - Добавлен width: 100% для растягивания на всю ячейку
   - Раздельные border-radius для start/middle/end сегментов
   - Улучшены визуальные индикаторы (‹ › с цветом)
   - Явные правила для всех комбинаций fc-event-start/end

Результаты:
✅ Многодневные события корректно растягиваются
✅ Четкая визуализация начала (левый радиус) и конца (правый радиус)
✅ Средние дни без закруглений (seamless переход)
✅ Индикаторы продолжения (‹ ›) белого цвета
✅ Совместимость с двухцветной схемой (календарь + событие)

Изменения:
- 2 files changed, 48 insertions(+), 51 deletions(-)
- Компилирован app.css
This commit is contained in:
admin i 2026-02-11 13:31:20 +03:00
parent 2521b0b053
commit f311d27dad
4 changed files with 43 additions and 40 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1003,62 +1003,52 @@ export function initCalendarWidget(options = {}) {
// Применяем современный стиль с двойным цветом
const eventEl = info.el;
// Проверяем, является ли событие многодневным
const isMultiDay = !info.event.allDay && info.event.start && info.event.end &&
(info.event.end.getDate() !== info.event.start.getDate() ||
info.event.end.getMonth() !== info.event.start.getMonth() ||
info.event.end.getFullYear() !== info.event.start.getFullYear());
// Проверяем тип сегмента многодневного события
const isStart = info.isStart;
const isEnd = info.isEnd;
if (calendarColor) {
// Если есть цвет календаря - показываем оба цвета
// Левая граница = цвет календаря, фон = цвет события (полупрозрачный)
eventEl.style.borderLeft = `4px solid ${calendarColor}`;
eventEl.setAttribute("data-has-calendar-color", "true");
eventEl.style.borderLeftColor = calendarColor;
eventEl.style.backgroundColor = eventColor + "CC"; // 80% прозрачности
eventEl.style.borderColor = eventColor;
// Добавляем тень для объёма
eventEl.style.boxShadow =
"0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)";
} else {
// Если нет цвета календаря - используем только цвет события
eventEl.style.backgroundColor = eventColor;
eventEl.style.borderColor = eventColor;
eventEl.style.borderLeft = `3px solid ${eventColor}`;
eventEl.style.boxShadow = "0 1px 2px rgba(0,0,0,0.1)";
}
// Улучшаем читаемость текста
eventEl.style.color = "#ffffff";
eventEl.style.textShadow = "0 1px 2px rgba(0,0,0,0.2)";
// Закругляем углы для современного вида
eventEl.style.borderRadius = "4px";
eventEl.style.overflow = "hidden";
// Добавляем отступы
eventEl.style.paddingLeft = "6px";
eventEl.style.paddingRight = "4px";
// Hover эффект
eventEl.addEventListener("mouseenter", () => {
eventEl.style.transform = "translateY(-1px)";
eventEl.style.boxShadow =
"0 4px 8px rgba(0,0,0,0.15), 0 2px 4px rgba(0,0,0,0.12)";
eventEl.style.transition = "all 0.2s ease";
eventEl.style.zIndex = "100";
});
eventEl.addEventListener("mouseleave", () => {
eventEl.style.transform = "translateY(0)";
if (calendarColor) {
eventEl.style.boxShadow =
"0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)";
} else {
eventEl.style.boxShadow = "0 1px 2px rgba(0,0,0,0.1)";
}
eventEl.style.transition = "all 0.2s ease";
});
// Особый стиль для ежегодных событий
if (recurrence === "annual") {
eventEl.setAttribute("data-recurrence", "annual");
}
// Hover эффект (только если не применяются автоматически)
if (!eventEl.classList.contains("fc-event")) {
eventEl.addEventListener("mouseenter", () => {
eventEl.style.transform = "translateY(-1px)";
eventEl.style.transition = "all 0.2s ease";
eventEl.style.zIndex = "100";
});
eventEl.addEventListener("mouseleave", () => {
eventEl.style.transform = "translateY(0)";
eventEl.style.transition = "all 0.2s ease";
});
}
// Добавляем обработчик правой кнопки мыши
info.el.addEventListener("contextmenu", (e) => {
e.preventDefault();

View File

@ -145,11 +145,17 @@ $event-max-lines: 2;
// Выравнивание контента
display: flex;
align-items: center;
// Растягиваем на всю ширину ячейки
width: 100% !important;
}
// Событие начинается (первый день)
.fc-event.fc-event-start:not(.fc-event-end) {
border-radius: $event-radius 0 0 $event-radius !important;
border-top-left-radius: $event-radius !important;
border-bottom-left-radius: $event-radius !important;
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
margin-right: 0 !important;
padding-right: ($event-padding-x + 2px) !important;
@ -165,6 +171,7 @@ $event-max-lines: 2;
font-size: 14px;
font-weight: bold;
opacity: 0.7;
color: rgba(255, 255, 255, 0.8);
}
}
@ -188,6 +195,7 @@ $event-max-lines: 2;
font-size: 14px;
font-weight: bold;
opacity: 0.7;
color: rgba(255, 255, 255, 0.8);
}
&::after {
@ -199,12 +207,16 @@ $event-max-lines: 2;
font-size: 14px;
font-weight: bold;
opacity: 0.7;
color: rgba(255, 255, 255, 0.8);
}
}
// Событие заканчивается (последний день)
.fc-event:not(.fc-event-start).fc-event-end {
border-radius: 0 $event-radius $event-radius 0 !important;
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
border-top-right-radius: $event-radius !important;
border-bottom-right-radius: $event-radius !important;
margin-left: 0 !important;
padding-left: ($event-padding-x + 2px) !important;
@ -220,6 +232,7 @@ $event-max-lines: 2;
font-size: 14px;
font-weight: bold;
opacity: 0.7;
color: rgba(255, 255, 255, 0.8);
}
}