<div class="calendar">
<div class="calendar__input">
<div class="calendar__icon"></div>
<input
data-required
id="date"
autocomplete="off"
value="Календарь"
type="text"
name="form[]"
readonly
class="_focus"
/>
</div>
<div class="calendar__content _hidden">
<div class="calendar__header">
<button class="calendar__btn-prev calendar-btn"></button>
<span></span>
<button class="calendar__btn-next calendar-btn"></button>
</div>
<div class="calendar__wrapper">
<div class="calendar__days"></div>
<div class="calendar__main"></div>
</div>
<div class="calendar__buttons">
<button type="button" class="calendar__button button">применить</button>
<button type="button" class="calendar__clear">сбросить фильтр</button>
</div>
</div>
</div>
.calendar {
position: relative;
}
.calendar__icon {
cursor: pointer;
position: absolute;
top: 51%;
transform: translate(0px, -50%);
transform: translate(0px, -50%);
transform: translate(0px, -50%);
left: 14px;
z-index: 5;
}
.calendar__icon::before {
font-size: 20px;
margin: -2px 0px 0px 0px;
}
.calendar__input {
position: relative;
}
.calendar__input input {
color: #a9a9a9;
cursor: pointer;
padding: 18px 18px 18px 50px;
}
.calendar__input._active input {
border: 1px solid #272727;
}
.calendar__content {
opacity: 1;
pointer-events: auto;
}
.calendar__content._hidden {
pointer-events: none;
opacity: 0;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
}
.calendar__header {
display: box;
display: flexbox;
display: flex;
box-align: center;
flex-align: center;
align-items: center;
margin: 0px 0px 12px 0px;
}
.calendar__header span {
font-family: "Montserrat", sans-serif;
font-weight: 600;
font-size: 16px;
line-height: 150%;
text-transform: uppercase;
text-align: center;
box-flex: 1;
flex: 1 1 auto;
flex: 1 1 auto;
}
.calendar__btn-prev {
width: 26px;
height: 24px;
display: box;
display: flexbox;
display: flex;
box-pack: center;
flex-pack: center;
justify-content: center;
box-align: center;
flex-align: center;
align-items: center;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
margin: 0px 10px 0px 0px;
}
.calendar__btn-prev::before {
font-size: 12px;
transform: rotate(-180deg);
transform: rotate(-180deg);
transform: rotate(-180deg);
}
.calendar__btn-prev:hover::before {
color: #127aee;
}
.calendar__btn-next {
width: 26px;
height: 24px;
display: box;
display: flexbox;
display: flex;
box-pack: center;
flex-pack: center;
justify-content: center;
box-align: center;
flex-align: center;
align-items: center;
margin: 0px 0px 0px 10px;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
}
.calendar__btn-next::before {
font-size: 12px;
}
.calendar__btn-next:hover::before {
color: #127aee;
}
.calendar__days {
display: grid;
display: grid;
column-gap: 4px;
column-gap: 4px;
column-gap: 4px;
grid-columns: (1fr)[7];
grid-template-columns: repeat(7, 1fr);
margin: 0px 0px 12px 0px;
pointer-events: none;
}
.calendar__main {
display: grid;
display: grid;
column-gap: 4px;
column-gap: 4px;
column-gap: 4px;
row-gap: 4px;
grid-columns: (1fr)[7];
grid-template-columns: repeat(7, 1fr);
grid-rows: (41px)[5];
grid-template-rows: repeat(5, 41px);
}
.calendar__buttons {
margin: 30px 0px 0px 0px;
}
.calendar__button {
width: 100%;
}
.calendar__clear {
width: 100%;
margin: 30px 0px 0px 0px;
font-family: "europeext", sans-serif;
font-weight: 700;
font-size: 16px;
line-height: 100%;
text-transform: uppercase;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
}
.calendar__clear:hover {
color: #127aee;
}
.calendar__popup {
display: none;
}
.cell_wrapper.current {
color: #272727;
}
.cell_wrapper {
cursor: pointer;
display: box;
display: flexbox;
display: flex;
box-pack: center;
flex-pack: center;
justify-content: center;
box-align: center;
flex-align: center;
align-items: center;
width: 41px;
height: 41px;
border-radius: 50%;
font-family: "Montserrat", sans-serif;
font-weight: 400;
font-size: 16px;
line-height: 140%;
text-align: center;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
transition: all 0.3s ease 0s;
border: 1px solid transparent;
background: transparent;
color: #a9a9a9;
}
.cell_wrapper.isCurrent {
border: 1px solid #272727;
background: transparent;
color: #272727;
}
.cell_wrapper.isCurrent.isSelected {
border: 1px solid #272727;
background: transparent;
color: #272727;
}
.cell_wrapper.cal_date.current.isSelected {
color: #fff;
background: #272727;
}
.cell_wrapper.cal_date.current.isSelected:last-child {
background: #841212;
}
.cell_wrapper.cal_date.current.isSelected:first-child {
background: #841212;
}
const calendar = document.querySelector(".calendar__main")
if (calendar) {
const input = document.querySelector("#date")
const calHeaderTitle = document.querySelector(".calendar__header span")
const calDays = document.querySelector(".calendar__days")
const days = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"]
const months = [
"Январь",
"Февраль",
"Март",
"Апрель",
"Май",
"Июнь",
"Июль",
"Август",
"Сентябрь",
"Октябрь",
"Ноябрь",
"Декабрь",
]
let oneDay = 60 * 60 * 24 * 1000
let todayTimestamp =
Date.now() -
(Date.now() % oneDay) +
new Date().getTimezoneOffset() * 1000 * 60
let selectedDay = todayTimestamp
const getNumberOfDays = (year, month) => {
return 40 - new Date(year, month, 40).getDate()
}
const getDayDetails = (args) => {
let date = args.index - args.firstDay
let day = args.index % 7
let prevMonth = args.month - 1
let prevYear = args.year
if (prevMonth < 0) {
prevMonth = 11
prevYear--
}
let prevMonthNumberOfDays = getNumberOfDays(prevYear, prevMonth)
let _date =
(date < 0 ? prevMonthNumberOfDays + date : date % args.numberOfDays) + 1
let month = date < 0 ? -1 : date >= args.numberOfDays ? 1 : 0
let timestamp = new Date(args.year, args.month, _date).getTime()
return {
date: _date,
day,
month,
timestamp,
dayString: days[day],
}
}
const getMonthDetails = (year, month) => {
let firstDay = new Date(year, month).getDay()
let numberOfDays = getNumberOfDays(year, month)
let monthArray = []
let rows = 5
let currentDay = null
let index = 0
let cols = 7
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
currentDay = getDayDetails({
index,
numberOfDays,
firstDay,
year,
month,
})
monthArray.push(currentDay)
index++
}
}
return monthArray
}
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth()
let monthDetails = getMonthDetails(year, month)
const isCurrentDay = (day, cell) => {
if (day.timestamp === todayTimestamp) {
cell.classList.add("isCurrent")
cell.classList.add("active")
}
}
const isSelectedDay = (day, cell) => {
if (day.timestamp === selectedDay) {
cell.classList.toggle("isSelected")
}
}
const getMonthStr = (month) =>
months[Math.max(Math.min(11, month), 0)] || "Month"
const setHeaderNav = (offset) => {
month = month + offset
if (month === -1) {
month = 11
year--
} else if (month === 12) {
month = 0
year++
}
monthDetails = getMonthDetails(year, month)
// console.log(getMonthDetails(year, month))
return {
year,
month,
monthDetails,
}
}
const setHeader = (year, month) => {
calHeaderTitle.innerHTML = getMonthStr(month) + " " + year
}
setHeader(year, month)
const getDateStringFromTimestamp = (timestamp) => {
let dateObject = new Date(timestamp)
let month = dateObject.getMonth()
let date = dateObject.getDate()
return `${getMonthStr(month)} ${date}, ${dateObject.getFullYear()}`
}
const setDateToInput = (timestamp) => {
let dateString = getDateStringFromTimestamp(timestamp)
//input.value = dateString;
}
setDateToInput(todayTimestamp)
for (let i = 0; i < days.length; i++) {
let div = document.createElement("div"),
span = document.createElement("span")
div.classList.add("cell_wrapper")
div.classList.add("cal_days")
span.classList.add("cell_item")
span.innerText = days[i].slice(0, 2)
div.appendChild(span)
calDays.appendChild(div)
}
const setCalBody = (monthDetails) => {
for (let i = 0; i < monthDetails.length; i++) {
let div = document.createElement("div"),
span = document.createElement("span")
div.classList.add("cell_wrapper")
div.classList.add("cal_date")
monthDetails[i].month === 0 && div.classList.add("current")
monthDetails[i].month === 0 && isCurrentDay(monthDetails[i], div)
span.classList.add("cell_item")
span.innerText = monthDetails[i].date
div.appendChild(span)
calendar.appendChild(div)
}
}
setCalBody(monthDetails)
const updateCalendar = (btn) => {
let newCal, offset
if (btn.classList.contains("calendar__btn-prev")) {
offset = -1
} else if (btn.classList.contains("calendar__btn-next")) {
offset = 1
}
newCal = setHeaderNav(offset)
setHeader(newCal.year, newCal.month)
calendar.innerHTML = ""
setCalBody(newCal.monthDetails)
}
// Only one calendar date is selected
const selectOnClick = () => {
document.querySelectorAll(".cell_wrapper").forEach((cell) => {
cell.classList.contains("isSelected") && cell.classList.remove("active")
if (
cell.classList.contains("isCurrent") &&
!cell.classList.contains("active")
) {
cell.querySelector("span").classList.add("inactive_indicator")
}
})
}
const updateInput = () => {
let currentDay = document.querySelector(".isCurrent")
document.querySelectorAll(".cell_wrapper").forEach((cell) => {
if (cell.classList.contains("current")) {
cell.addEventListener("click", (e) => {
let cell_date = e.target.textContent
currentDay !== null && currentDay.classList.remove("active")
for (let i = 0; i < monthDetails.length; i++) {
if (monthDetails[i].month === 0) {
if (monthDetails[i].date.toString() === cell_date) {
selectedDay = monthDetails[i].timestamp
setDateToInput(selectedDay)
selectOnClick()
isSelectedDay(monthDetails[i], cell)
cell
.querySelector("span")
.classList.contains("inactive_indicator") &&
cell
.querySelector("span")
.classList.remove("inactive_indicator")
}
}
}
})
}
})
}
updateInput()
document.querySelectorAll(".calendar-btn").forEach((btn) => {
btn.addEventListener("click", () => {
updateCalendar(btn)
updateInput()
})
})
input.addEventListener("click", () => {
document.querySelector(".calendar__content").classList.toggle("_hidden")
document.querySelector(".calendar__input").classList.toggle("_active")
document.querySelector("#date").classList.toggle("_focus")
})
window.addEventListener("click", (e) => {
const target = e.target
if (
!target.closest("#date") &&
!target.closest(".calendar__input") &&
!target.closest(".calendar__content")
) {
document.querySelector(".calendar__content").classList.add("_hidden")
document.querySelector(".calendar__input").classList.remove("_active")
document.querySelector("#date").classList.add("_focus")
}
})
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.