Created
March 29, 2018 05:33
-
-
Save erakor/07f9145ce8196b4a9d747b5ec6eea62a to your computer and use it in GitHub Desktop.
Calendar.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <div id="calendar"></div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| $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