134 lines
5.6 KiB
Twig
134 lines
5.6 KiB
Twig
{#
|
||
calendar.twig - Универсальный компонент календаря
|
||
|
||
Параметры:
|
||
- events: Массив событий
|
||
Пример:
|
||
events: [
|
||
{
|
||
id: 1,
|
||
title: 'Событие 1',
|
||
date: '2026-01-15',
|
||
color: '#3B82F6',
|
||
url: '/path/to/event'
|
||
}
|
||
]
|
||
- currentMonth: Текущий месяц в формате YYYY-MM
|
||
- prevMonth: URL или параметр для предыдущего месяца
|
||
- nextMonth: URL или параметр для следующего месяца
|
||
- eventComponent: Имя Twig компонента для рендеринга событий (опционально)
|
||
- onEventClick: JavaScript функция при клике на событие (опционально)
|
||
- showLegend: Показывать легенду (опционально, по умолчанию true)
|
||
- legend: Массив для легенды (опционально)
|
||
Пример:
|
||
legend: [
|
||
{ name: 'Этап 1', color: '#3B82F6' }
|
||
]
|
||
#}
|
||
{# Навигация по месяцам #}
|
||
{% if showNavigation|default(true) %}
|
||
<div class="card shadow-sm mb-4">
|
||
<div class="card-body d-flex justify-content-between align-items-center">
|
||
<a href="{{ prevMonth }}" class="btn btn-outline-secondary">
|
||
<i class="fa-solid fa-chevron-left me-1"></i>Предыдущий
|
||
</a>
|
||
<h5 class="mb-0">{{ monthName }}</h5>
|
||
<a href="{{ nextMonth }}" class="btn btn-outline-secondary">
|
||
Следующий<i class="fa-solid fa-chevron-right ms-1"></i>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
{# Календарь #}
|
||
<div class="card shadow-sm">
|
||
<div class="card-body p-0">
|
||
<div class="calendar">
|
||
{# Дни недели #}
|
||
<div class="calendar-header bg-light">
|
||
{% for day in ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'] %}
|
||
<div class="calendar-header-cell text-center py-2 text-muted small fw-normal">
|
||
{{ day }}
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
|
||
{# Сетка календаря #}
|
||
<div class="calendar-grid">
|
||
{# Пустые ячейки до первого дня #}
|
||
{% for i in 0..(firstDayOfWeek - 1) %}
|
||
<div class="calendar-cell bg-light"></div>
|
||
{% endfor %}
|
||
|
||
{# Дни месяца #}
|
||
{% for day in 1..daysInMonth %}
|
||
{% set dateStr = currentMonth ~ '-' ~ (day < 10 ? '0' ~ day : day) %}
|
||
{% set dayEvents = eventsByDate[dateStr]|default([]) %}
|
||
{% set isToday = dateStr == today %}
|
||
|
||
<div class="calendar-cell {{ isToday ? 'calendar-cell-today' : '' }}">
|
||
<div class="calendar-day-number {{ isToday ? 'text-primary fw-bold' : '' }}">
|
||
{{ day }}
|
||
</div>
|
||
|
||
<div class="calendar-events">
|
||
{% for event in dayEvents|slice(0, 3) %}
|
||
{% if eventComponent is defined %}
|
||
{{ include(eventComponent, {event: event}) }}
|
||
{% else %}
|
||
{{ include('@components/calendar/default_event.twig', {event: event, onEventClick: onEventClick|default('')}) }}
|
||
{% endif %}
|
||
{% endfor %}
|
||
|
||
{% if dayEvents|length > 3 %}
|
||
<div class="calendar-events-more text-muted small">
|
||
+{{ dayEvents|length - 3 }} ещё
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
|
||
{# Пустые ячейки после последнего дня #}
|
||
{% set remainingCells = 7 - ((firstDayOfWeek + daysInMonth) % 7) %}
|
||
{% if remainingCells < 7 %}
|
||
{% for i in 1..remainingCells %}
|
||
<div class="calendar-cell bg-light"></div>
|
||
{% endfor %}
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{# Легенда #}
|
||
{% if showLegend|default(true) and (legend is defined or events is defined) %}
|
||
<div class="card shadow-sm mt-4">
|
||
<div class="card-body">
|
||
<h6 class="card-title">Легенда</h6>
|
||
<div class="d-flex flex-wrap gap-2">
|
||
{% if legend is defined %}
|
||
{% for item in legend %}
|
||
<span class="badge"
|
||
style="background-color: {{ item.color }}20; color: {{ item.color }}; border: 1px solid {{ item.color }}40;">
|
||
{{ item.name }}
|
||
</span>
|
||
{% endfor %}
|
||
{% else %}
|
||
{# Автоматическая легенда из типов событий #}
|
||
{% set uniqueColors = {} %}
|
||
{% for event in events %}
|
||
{% if event.color is defined and event.color not in uniqueColors %}
|
||
<span class="badge"
|
||
style="background-color: {{ event.color }}20; color: {{ event.color }}; border: 1px solid {{ event.color }}40;">
|
||
{{ event.title }}
|
||
</span>
|
||
{% set uniqueColors = uniqueColors|merge([event.color]) %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|