Calendar componentAvailable since EcoComposer 2.2

Classical calendar example :

May 2025

The default values are :

calendar--actual-week--background-color : 'calendar--actual-week--background-color', calendar--actual-week--background-image : 'calendar--actual-week--background-image', calendar--actual-week--color : 'calendar--actual-week--color', calendar--background--color : 'calendar--background--color', calendar--background--lines-color : 'calendar--background--lines-color', calendar--days--headers--background-color : 'calendar--days--headers--background-color', calendar--days--headers--background-color--hover : 'calendar--days--headers--background-color--hover', calendar--days--headers--color : 'calendar--days--headers--color', calendar--days--today--background-color : 'calendar--days--today--background-color', calendar--days--today-hour--background-color : 'calendar--days--today-hour--background-color', calendar--event--border : 'calendar--event--border', calendar--event--color : 'calendar--event--color', calendar--event--drag-hover-error--box-shadow : 'calendar--event--drag-hover-error--box-shadow', calendar--event--drag-hover--box-shadow : 'calendar--event--drag-hover--box-shadow', calendar--sidebar--today-date--color : 'calendar--sidebar--today-date--color', calendar--timeline--background-color : 'calendar--timeline--background-color', calendar--timeline--color : 'calendar--timeline--color', day--background-type : 'linear', // 'linear', 'radial' or 'no' days-header--font-size : 2rem * theming.$font-size, days-header--height : 4rem * theming.$font-size, event--background-type : 'linear', // 'linear', 'radial' or 'no' events : ( first : #fdd, second : #ffa, third : #eff, fourth : #dfe ), font-family : theming.$font-family, gap-day : .1rem * theming.$font-size, gap-hour : 1rem * theming.$font-size, gap-date-between-number-and-string : 1rem * theming.$font-size, num-days : 5, num-hours : 10, print : false, sidebar-width : 17rem * theming.$font-size, suffix : '', themes : ( light : ( default--calendar--actual-week--background-color : #00ffb2, default--calendar--actual-week--background-image : utils.fn-linear-gradient(45, #00ffb2), default--calendar--actual-week--color : #fff, default--calendar--background--color : #f2f2f2, default--calendar--background--lines-color : #ddd, default--calendar--days--headers--background-color : #eee, default--calendar--days--headers--background-color--hover : #ddd, default--calendar--days--headers--color : #333, default--calendar--days--today--background-color : #00ffb2, default--calendar--days--today-hour--background-color : #f55, default--calendar--event--border : 1px solid #f2d3d8, default--calendar--event--color : #444, default--calendar--event--drag-hover-error--box-shadow : 0 0 .8rem * theming.$font-size .1rem * theming.$font-size #f44, default--calendar--event--drag-hover--box-shadow : 0 0 .5rem * theming.$font-size #333, default--calendar--sidebar--today-date--color : #eee, default--calendar--timeline--background-color : #eee, default--calendar--timeline--color : #444 ), dark : ( default--calendar--actual-week--background-color : #00ffb2, default--calendar--actual-week--background-image : utils.fn-linear-gradient(45, #00ffb2), default--calendar--actual-week--color : #fff, default--calendar--background--color : #333, // main background under cells default--calendar--background--lines-color : #555, // horizontal lines default--calendar--days--headers--background-color : #444, // day headers default--calendar--days--headers--background-color--hover : #555, // days headers hover background color default--calendar--days--headers--color : #ccc, // days headers text color default--calendar--days--today--background-color : #0a7, // today header background color default--calendar--days--today-hour--background-color : #f55, // today hour line background color default--calendar--event--border : 1px solid #555, // border around cells default--calendar--event--color : #444, // event cell text color default--calendar--event--drag-hover-error--box-shadow : 0 0 .8rem * theming.$font-size .1rem * theming.$font-size #f44, // event dragged on wrong area, added border default--calendar--event--drag-hover--box-shadow : 0 0 .5rem * theming.$font-size #333, // event dragged, hovering a day, drop shadow default--calendar--sidebar--today-date--color : #eee, default--calendar--timeline--background-color : #444, // timeline headers default--calendar--timeline--color : #fff // timeline text color ) ), time-height : 6rem * theming.$font-size, timeline-width : 6rem * theming.$font-size, week-height : 12rem * theming.$font-size

We can implement it that way :

@include calendar.init(); @include calendar.create(); @include calendar.create( ( suffix : '-2', num-hours : 9, ) );

We can implement it that way :

Beware, there is only the code of the day view here.

<?php const MINUTES_IN_AN_HOUR = 60, DAYS_HEADER_HEIGHT = '4', TIME_HEIGHT = 6; ?><div class=calendar-component> <script nonce=yourGeneratedNonce> window.calendarContainers = {}; // put your calendar containers JSON data here window.calendarEvents = {}; // put your calendar events JSON data here </script> <style nonce=yourGeneratedNonce><?php $colors = '@supports (accent-color: #000) {'; foreach ($calendarContainers[$displayedCalendarContainerId] as $calendarId => $calendar) { ?>#cal-check-<?= $calendarId ?>:not(:checked)~.cal-container .cal--event-<?= $calendarId ?> { opacity : 0; }<?php ob_start(); ?> #cal-check-<?= $calendarId ?> { accent-color: <?= $calendar['color'] ?> } <?php $colors .= ob_get_clean(); } echo $colors . '}'; for ($dayToStyleIndex = 0; $dayToStyleIndex < 5; ++$dayToStyleIndex) { ?> .cal--day<?= $dayToStyleIndex ?>:target { display: block; } <?php } ?> .cal--date-header:target ~ div { display : none; } </style> <p class="cal cal--sidebar--today-date"><?= $todayDate->format('F Y')?></p> <div class=cal--sidebar> <button type="button" class="cal ripple--cal--previous -cal--previous" title="Previous week"><</button><!-- --> <button type="button" class="cal ripple--cal--change-date -cal--change-date" title="Change the displayed week" data-day-number="<?= $todayDateString ?>" data-day-name="<?= $todayDate->format('D') ?>" data-week="<?= $week ?>" data-month-number="<?= $todayDate->format('m') ?>" data-year="<?= $todayDate->format('Y') ?>"> Week <?= $week ?></button><!-- --><button type="button" class="cal ripple--cal--next -cal--next" title="Next week">></button> </div><?php const OPTION_WEEK_KEY = 1, OPTIONS_LABELS = ['Day', 'Week', 'Month', 'Year']; ?><div class="cal--select select select-container"> <button type="button" role=menu class="cal--select-value select select-value" aria-labelledby="select-value--label"> <span id=select-value--label class="select select-value--label cal--select-value--label"><?= OPTIONS_LABELS[OPTION_WEEK_KEY] ?></span> <span>&#x25bc;&#xfe0e;</span> </button> <div class="cal--select-container select select-list select-container"><?php foreach (OPTIONS_LABELS as $optionKey => $option) { $lcFirstOption = lcfirst($option); ?> <input type=radio role=menuitem id="chk-<?= $lcFirstOption ?>-option" name=calendar--change-view class="select select-item--activator" value="<?= $option ?>"<?php if ($optionKey === OPTION_WEEK_KEY) echo ' checked'; ?>/> <label for="chk-<?= $lcFirstOption ?>-option" class="select select-item--label -calendar--change-view"><?= $option ?></label><?php } ?></div> </div><?php foreach ($calendarContainers[$displayedCalendarContainerId] as $calendarId => $calendar) { ?> <label for="cal-check-<?= $calendarId ?>" class=cal-check title="Toggle the display of events related to '<?= $calendar['name'] ?>'"><?= $calendar['name'] ?></label> <input type="checkbox" id="cal-check-<?= $calendarId ?>" checked title="Toggle the display of events related to '<?= $calendar['name'] ?>'"/> <?php } ?> <div class="cal cal-container" data-calendar-container-id="<?= $displayedCalendarContainerId ?>"> <div class="cal calendar"> <div class="cal cal--timeline"> <div class="cal cal--timeline--spacer"><?php $offset = (new DateTimeZone(date_default_timezone_get()))->getOffset($todayDate) / 3600; echo 'GMT'; if ($offset >= 0) echo '+'; echo $offset; ?></div> <div class="cal cal--timeline--hours"> <?php for ($hour = $startHour; $hour < $endHour; ++$hour) { ?><div><?php if ($hour < 10) echo '0'; echo $hour . ':00'; ?></div><?php } ?> </div> </div> <div class="cal cal--days"> <div id=cal--day--dummy-activator0></div> <?php $dayHtml = ''; ob_start(); $dayPlanning( 0, $firstMondayOfThisWeek, $calendarEvents[$displayedCalendarContainerId], $todayDateString ); $dayHtml .= ob_get_clean(); $dayPlanning = function (int $dayIndex, DateTime $date, array $events, string $todayDateString) use ($viewsPath) : void { $dayDateNumber = $date->format('d'); $isToday = $dayDateNumber === $todayDateString; $fullDate = $date->format('Y-m-d'); $dayDateName = $date->format('D'); ?><div class=cal--date-header><?php if ($isToday) { ?> <hr class="cal cal--days--date--hour"/><?php } ?><a href="#cal--day--dummy-activator<?= $dayIndex ?>" class="cal cal--days--date<?php if ($isToday) echo ' cal--days--today'; ?>" title="Only show this day" data-day-number="<?= $dayDateNumber ?>" data-day-name="<?= $dayDateName ?>"> <p class="cal cal--days--date--num"><?= $dayDateNumber ?></p> <p class="cal cal--days--date--day"><?= $dayDateName ?></p> </a> <div class="cal cal--days--events -cal--day--<?= $fullDate ?>" data-date="<?= $fullDate?>"><?php foreach ($events as $eventId => $eventData) { $event = $eventData['event']; if ($dayDateNumber === $event['fromDate']->format('d')) { $fromMinutes = $event['fromDate']->format('i'); $toMinutes = $event['toDate']->format('i'); ?> <a href="#cal--event-modal" class="cal cal--days--events--event from-<?= $event['fromDate']->format('G') ?> to-<?php echo $event['toDate'] ->format('G'), ' ', $event['cssClass'], ' cal--event-', $eventData['calendarId']; if ($fromMinutes !== '00') echo ' cal--from--min' . $fromMinutes; if ($toMinutes !== '00') echo ' cal--to--min' . $toMinutes; ?>" data-event-id="<?= $eventId ?>" data-event-title="<?= $event['title'] ?>" data-event-description="<?= $event['description'] ?>" draggable="true"> <p class="cal cal--days--events--event--title"><?= $event['title'] ?></p> <p class=-cal--hours><?= $event['fromDate']->format('H:i') ?> - <?= $event['toDate']->format('H:i') ?></p> </a> <?php } } ?></div> </div><?php }; for ($day = 1; $day < $daysByWeek; ++$day) { ob_start(); $dayPlanning( $day, $firstMondayOfThisWeek->modify('+1 day'), $calendarEvents[$displayedCalendarContainerId], $todayDateString ); $dayHtml .= ob_get_clean(); ?><div id="cal--day--dummy-activator<?= $day ?>"></div> <?php } echo $dayHtml; </div> </div> <div class="cal cal--days--lines"></div> <div id=cal--event-modal class=modal--container> <form class="modal--container--element event--modal" method="post"> <a href="#" role=button class="ripple-2 modal--btn--close" aria-label="Close">X</a> <div class=event--modal--group> <label for="event--title" class="modal--event-label label required">Title</label> <input id=event--title name=event--title class="modal--event-input field" required/> </div> <div class=event--modal--group> <label for="event--date" class="modal--event-label label required">Date</label> <input id=event--date name=event--date type="date" class="modal--event-input field" required/> </div> <div class=event--modal--group> <label for="event--hour-from" class="modal--event-label label required">From</label> <input id=event--hour-from name=event--hour-from type="time" class="modal--event-input field" required/> </div> <div class=event--modal--group> <label for="event--hour-to" class="modal--event-label label required">To</label> <input id=event--hour-to name=event--hour-to type="time" class="modal--event-input field" required/> </div> <label for="event--description" class="label required">Description</label> <textarea id=event--description name=event--description class="modal--event-description field" required></textarea> <button type="submit" class="ripple modal--btn--send -save-button margin-t10b20">Save</button> </form> </div> </div> </div>
^