Skip to content

Instantly share code, notes, and snippets.

@erakor
Created March 29, 2018 05:33
Show Gist options
  • Select an option

  • Save erakor/07f9145ce8196b4a9d747b5ec6eea62a to your computer and use it in GitHub Desktop.

Select an option

Save erakor/07f9145ce8196b4a9d747b5ec6eea62a to your computer and use it in GitHub Desktop.
Calendar.md
<div id="calendar"></div>
class Calendar {
// Constructor
// Set defaults if undefined
constructor(
month = new Date().getMonth(),
year = new Date().getFullYear()
) {
// Set the current month, year
this.date = new Date();
this.currentMonth = month;
this.currentYear = year
this.dayNames = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
this.monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
};
// returns Day count for a month
getDayCountInMonth(month, year) {
// Day 0 is the last day in the previous month
return new Date(year, month + 1, 0).getDate();
}
// returns Name of the month
getMonthName(monthNumber) {
return this.monthNames[monthNumber];
}
// returns Day of the week for the first day of a month
// [0 = Sunday - 6 = Saturday]
getFirstDayOfTheMonth(month, year) {
return new Date(year, month, 1).getDay();
}
// Builds and returns month data object
getMonthData() {
let monthData = {
month: this.currentMonth,
year: this.currentYear,
daysInMonth: this.getDayCountInMonth(this.currentMonth, this.currentYear),
firstDayOfMonth: this.getFirstDayOfTheMonth(this.currentMonth, this.currentYear)
}
return monthData;
}
// increments month and year then
// renders calendar with new data
goToNextMonth() {
// if month is Dec (11),
// go to Jan (0) of the following year
if ( this.currentMonth == 11 ) {
this.currentMonth = 0;
this.currentYear++;
} else {
this.currentMonth++;
}
this.renderCalendar();
}
// reduces month and year then
// renders calendar with new data
goToPreviousMonth() {
// if month is Jan (0),
// go to Dec (11) of the previous year
if ( this.currentMonth == 0 ) {
this.currentMonth = 11;
this.currentYear--;
} else {
this.currentMonth--;
}
this.renderCalendar();
};
// returns a string made up of
// divs containing the days of the week
buildHeaderRow() {
// we have to start with an empty var
// because we are adding div to current one
let headerRow = '';
this.dayNames.forEach((dayName) => {
headerRow += `<div class='calendar-week__day'>${dayName}</div>`;
})
return headerRow;
}
// returns string with as many divs
// as there are days in the month
buildWeekRows(monthData) {
// we don't have to start with an empty var
// because we start by overridding tje current one
let weekRows;
let day = 1;
const firstDay = monthData.firstDayOfMonth;
const dayCount = monthData.daysInMonth;
// Adds empty divs when the first day
// of the month isn't a Monday
weekRows = '<div></div>'.repeat(firstDay);
while ( day <= dayCount ) {
weekRows += `<div class='calendar__day'>${day}</div>`;
day++;
}
return weekRows;
}
// returns string with current month and year to show
getShowDate(monthData) {
let showMonth = this.getMonthName(monthData.month);
let showYear = monthData.year;
return `${showMonth} ${showYear}`;
}
buildNextButton() {
return `
<button class='calendar__next'>
<svg viewBox='0 0 1792 1792' xmlns='http://www.w3.org/2000/svg'>
<!-- leave title for accessibility! -->
<title>Go to next month</title>
<path d="M1152 896q0 26-19 45l-448 448q-19 19-45 19t-45-19-19-45v-896q0-26 19-45t45-19 45 19l448 448q19 19 19 45z"/>
</svg>
</button>`;
}
buildPreviousButton() {
return `
<button class='calendar__previous'>
<svg viewBox="0 0 1792 1792" xmlns='http://www.w3.org/2000/svg'>
<!-- leave title for accessibility! -->
<title>Go to previous month</title>
<path d="M1216 448v896q0 26-19 45t-45 19-45-19l-448-448q-19-19-19-45t19-45l448-448q19-19 45-19t45 19 19 45z"/>
</svg>
</button>`;
}
renderCalendar() {
let monthData = this.getMonthData();
const showDate = this.getShowDate(monthData);
const showHeaderRow = this.buildHeaderRow();
const showWeekRows = this.buildWeekRows(monthData);
const previousButton = this.buildPreviousButton();
const nextButton = this.buildNextButton();
// Time to start building our calendar
const calendarContainer = document.getElementById('calendar');
calendarContainer.innerHTML = `
<h1 class='calendar__title'>${showDate}</h1>
<div class='calendar-container'>
${previousButton}
<div class='calendar-grid calendar-spacing'>
<div class='calendar-week calendar-spacing'>
${showHeaderRow}
</div>
<div class='calendar-days calendar-spacing'>
${showWeekRows}
</div>
</div>
${nextButton}
</div>
`;
}
}
const calendar = new Calendar();
calendar.renderCalendar();
// Listen to clicks on each buttons
// event delegation because buttons were added dynamically
document.addEventListener('click', (e) => {
if (e.target.classList.contains('calendar__previous')) {
calendar.goToPreviousMonth();
}
if (e.target.classList.contains('calendar__next')) {
calendar.goToNextMonth();
}
}, false);
$spacing: 20px;
// Sass mixin to reset button styling
@mixin reset-button {
border: none;
margin: 0;
padding: 0;
width: auto;
overflow: visible;
background: transparent;
}
body {
font-family: Helvetica, sans-serif;
}
.calendar-container {
display: flex;
align-items: center;
justify-content: center;
}
.calendar__title {
text-align: center;
}
// Util class to handle grid spacing
.calendar-spacing {
display: grid;
grid-gap: $spacing;
text-align: center;
}
.calendar-grid {
border: 1px solid #ccc;
border-radius: 5px;
padding: $spacing;
}
.calendar-week,
.calendar-days {
grid-template-columns: repeat(7, 1fr);
}
// Color weekend days
.calendar-week__day,
.calendar__day {
&:nth-child(0),
&:nth-child(7n+1),
&:nth-child(7n) {
color: red;
}
}
.calendar-week {
font-weight: bold;
padding-bottom: $spacing;
border-bottom: 2px solid #ccc;
}
.calendar__next,
.calendar__previous{
@include reset-button;
width: 50px;
position: relative;
// transparent layer required above the buttons
// to cover the svg because clicks/taps and SVGs
// are not getting along very well.
&::after {
width: 50px;
height: 50px;
display: block;
top: 0;
left: 0;
position: absolute;
content: " ";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment