<div id="wrap-calendar"></div>
* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
	font-family: sans-serif;
	line-height: 1.5;
	font-size: 16px;
	font-weight: 400;
	color: #333;
}

#wrap-calendar {
	display: grid;
	grid-template-columns: repeat(7, 1fr);
/* 	grid-template-rows: repeat(5, 1fr); */
	height: 420px;
	max-width: 580px;
	margin: 50px auto;
}

.day { 
	display: flex;
	justify-content: flex-start;
	align-items: flex-end;
	min-height: 80px;
	margin-top: -1px;
	margin-right: -1px;
	padding: 10px;
	position: relative;
	border: 1px solid #dedede;
	cursor: not-allowed;
	transition: all .2s ease-in-out;
}

.day-name {
	position: absolute;
	top: 10px;
	right: 10px;
	font-size: 12px;
	font-weight: 200;
	text-transform: capitalize;
}

.weekend, .weekend span { color: coral; }

.day .current { 
	display: flex;
	justify-content: center;
	align-items: center;
	width: 25px;
	height: 25px;
	padding-top: 2px;
	color: #fff;
	background: coral;
	border-radius: 50%;
}

.checkable { cursor: pointer; }
.checkable:hover { background: #ccc; }
.checkable:hover span { color: #fff; }

.open {
	background: #4574EB;
	cursor: pointer; 
}

.open span { color: #fff; }

.open .current { color: #4574EB; background: #fff; }

.mute span:first-child { color: #ccc; }

/* EVENT */
.event {
	grid-column: 1/8;
	height: 0px;
	background: #ccc;
	overflow: hidden;
	transition: all .2s;
}

.event-content {
	padding: 20px;
}

.event-content h2 span:first-child {
	text-transform: capitalize;
}

.event-content h2 span{
	font-size: 20px;
	font-weight: 600;
}

.event-content .event-description {
	font-size: 14px;
	font-weight: 200;
}

.day.open ~ .event:nth-child(n1) {
	height: 150px;
}
const wrapCalendar = document.querySelector('#wrap-calendar');
const now = new Date();
// текущая дата
const todayDate = now.getDate();
// текущий месяц
const todayMonth = now.getMonth();
// текущий год
const todayYear = now.getFullYear();
// последнее число месяца 28, 29, 30, 31
const lastDateOfMonth = new Date(todayYear, todayMonth + 1, 0).getDate();
// номер дня недели с которого начинается месяц
const startDay = new Date(todayYear, todayMonth, 1).getDay();
// название дня недели с которого начинается месяц
const nameStartDay = new Date(todayYear, todayMonth, 1).toLocaleString("ru", { weekday: "short" });
// дни недель
const weekDays = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
// дни недель с полным названием
const weekDaysFull = ['понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'];
// число месяца
let d = 1;
// номер дня недели
let weekday = 0;

for ( let i = 1; i <= 42; i++) {
	let weekend = (i % 7 === 6) || (i % 7 === 0) ? 'weekend' : '';
	let date;
	
	// задаем число в диапазоне месяца
	switch (true) {
		case (i === startDay): 
			date = d++;
			break;

		case (i <= lastDateOfMonth + 1 && i > startDay): 
			date = d++;
			break;
		
		default:
			date = '-';
			break;
	}
	
	let current = (date === todayDate) ? 'current' : '';
	let checkable = (date !== '-') ? 'checkable' : '';
	let mute = (date !== '-') ? '' : 'mute';
	// шаблон окна event события
	let eventTemplate = () => {
		return `<div class="event">
				<div class="event-content">
					<h2>Event title</h2>
					<div class="event-description"> Lorem ipsum — классический текст-«рыба». Является искажённым отрывком из философского трактата Марка Туллия Цицерона «О пределах добра и зла», написанного в 45 году до н. э.</div>
				</div> 
			</div>`
	};
		
		wrapCalendar.insertAdjacentHTML('beforeend', 
		`<div class="day ${weekend} ${checkable} ${mute}"
						data-order = "${i}"
						data-date = "${date}"
						data-name = "${weekDaysFull[weekday]}"
						data-full-date = "${(date !== '-') ? getFullDate(date - todayDate)['full'] : ''}"
						data-event = "Какие-то события в этот день....">
				<span class="${current}">${date}</span>
				<span class="day-name">${(i <= 7 ) ? weekDays[i - 1] : ''}</span>
			</div>
			${(i % 7 === 0) ? eventTemplate() : ''}`
		);
	
	
	// название дня недели
	if (weekday < 7) weekday++;
	if (i % 7 === 0) weekday = 0;
}

// событие клика - переключает класс checked выбранному дню
const days = wrapCalendar.querySelectorAll('.checkable')
const events = document.querySelectorAll('.event');

days.forEach((day, index) => {	
		
	day.addEventListener('click', (e) => {
		const checkable = day.classList.contains('checkable');
		const open = day.classList.contains('open');

		if (checkable) {
			console.log('open', e.target.classList.contains('checkable'));
			day.classList.toggle('open');
			for (let i = 0; i < days.length; i++) days[i].classList.remove('checkable');
			for (let i = 0; i < events.length; i++) {
				events[i].querySelector('h2').innerHTML = `
					<span>${day.dataset.fullDate.split(',')[0]},</span>
					<span>${day.dataset.fullDate.split(',')[1]}</span>`;
				events[i].querySelector('.event-description').innerHTML = `${day.dataset.event}`
			}
			// открывает нужный блок event
			switch (true) {
				case (day.dataset.order <= 7):
					events[0].style.height = '150px';
					break;
				case (day.dataset.order <= 13):
					events[1].style.height = '150px';
					break;
				case (day.dataset.order <= 21):
					events[2].style.height = '150px';
					break;
				case (day.dataset.order <= 29):
					events[3].style.height = '150px';
					break;
				case (day.dataset.order <= 42):
					events[4].style.height = '150px';
					break;
				case (day.dataset.order <= 7):
					events[5].style.height = '150px';
					break;
			}
		} 
		else if (open) {
			console.log('close', e.target.classList.contains('open'));
			day.classList.remove('open');
			for (let i = 0; i < days.length; i++) days[i].classList.add('checkable');
			for (let i = 0; i < events.length; i++) events[i].style.height = '0px';
		}			
	})
})

/* 
	Полная информация о дате
*/
function getFullDate(d = 0) {
	const today = new Date();
	today.setDate(today.getDate() + parseInt(d));
	const full = today.toLocaleString("ru", {weekday: "long", month: "long", day: "numeric", year: "numeric"});
	const currentWeekDay = today.toLocaleString("ru", { weekday: "long" });
	const weekDayShort = today.toLocaleString("ru", { weekday: "short" });
	const currentDate = parseInt(today.toLocaleString("ru", { day: "numeric" }), 10);
	const nameOfMonth = today.toLocaleString("ru", { month: "long" });
	const nameOfMonthShort = today.toLocaleString("ru", { month: "short" });
	const numberOfMonth = parseInt(today.toLocaleString("ru", { month: "numeric" }), 10);
	const year = parseInt(today.toLocaleString("ru", { year: "numeric" }), 10);
	const lastDateOfMonth = new Date(year, numberOfMonth, 0).getDate();
	const monthStartWeekDay = new Date(year, numberOfMonth - 1, 1).toLocaleString("ru", { weekday: "short" });
	const monthEndWeekDay = new Date(year, numberOfMonth, 0).toLocaleString("ru", {weekday: "short"});
	return {
		currentWeekDay: currentWeekDay,
		weekdayShort: weekDayShort,
		currentDate: currentDate,
		nameOfMonth: nameOfMonth,
		nameOfMonth: nameOfMonth,
		numberOfMonth: numberOfMonth,
		year: year,
		full: full,
		lastDateOfMonth: lastDateOfMonth,
		monthStartWeekDay: monthStartWeekDay,
		monthEndWeekDay: monthEndWeekDay
	};
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.