Last active
July 18, 2019 22:05
-
-
Save maburdi94/1cccc6cecdd9717292f38f45b583c5d3 to your computer and use it in GitHub Desktop.
Infinite scrolling web component calendar
This file contains 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 ScrollCalendar extends HTMLElement { | |
connectedCallback() { | |
let observer = new IntersectionObserver((entries) => { | |
let el = entries[0]; | |
if (el.isIntersecting) { | |
observer.unobserve(this.firstElementChild); | |
observer.unobserve(this.lastElementChild); | |
this.update(el.target); | |
observer.observe(this.firstElementChild); | |
observer.observe(this.lastElementChild); | |
} | |
}); | |
observer.observe(this.firstElementChild); | |
observer.observe(this.lastElementChild); | |
} | |
render() { | |
let date = this.getAttribute('date'); | |
date = date ? new Date(date) : new Date(); | |
this.innerHTML = ''; | |
date.setMonth(date.getMonth() - 5); | |
for (let i = 0; i < 11; i++) { | |
this.appendChild(ScrollCalendar.renderElement(date)); | |
date.setMonth(date.getMonth() + 1); | |
} | |
this.children[5].scrollIntoView(); | |
} | |
static renderElement(date) { | |
const today = new Date(); | |
let year = date.getFullYear(); | |
let month = date.getMonth(); | |
date.setUTCHours(0,0,0,0); | |
let container = document.createElement('div'); | |
container.classList.add('month'); | |
let monthLabel = document.createElement('h2'); | |
monthLabel.classList.add('label'); | |
monthLabel.innerText = date.toLocaleString('en-us', { month: 'long', year: 'numeric' }); | |
let header = document.createElement('header'); | |
header.classList.add('weekdays'); | |
header.style.display = 'grid'; | |
header.style.gridTemplateColumns = 'repeat(7, 1fr)'; | |
header.innerHTML = ` | |
<span>S</span> | |
<span>M</span> | |
<span>T</span> | |
<span>W</span> | |
<span>T</span> | |
<span>F</span> | |
<span>S</span> | |
`; | |
let dates = document.createElement('div'); | |
dates.classList.add('dates'); | |
dates.style.display = 'grid'; | |
dates.style.gridTemplateColumns = 'repeat(7, 1fr)'; | |
dates.style.gridAutoRows = '1fr'; | |
const NUM_DAYS_IN_MONTH = new Date(year, month + 1, 0).getDate(); | |
for(let i = 1; i <= NUM_DAYS_IN_MONTH; i++) { | |
let date = new Date(year, month, i); | |
let cell = document.createElement('div'); | |
cell.classList.add('date'); | |
cell.innerText = i; | |
if ((i === today.getDate()) | |
&& ((date.getMonth() === today.getMonth()) | |
&& (date.getFullYear() === today.getFullYear()))) { | |
cell.classList.add('today'); | |
} | |
if (i === 1) { | |
cell.style.gridColumnStart = date.getDay() + 1; | |
} | |
dates.appendChild(cell); | |
} | |
container.dataset.date = date.toISOString(); | |
container.appendChild(monthLabel); | |
container.appendChild(header); | |
container.appendChild(dates); | |
return container; | |
} | |
update(target) { | |
let date = new Date(target.dataset.date); | |
const SCROLL_UP = target === this.firstElementChild; | |
for (let i = 0; i < 5; i++) { | |
if (SCROLL_UP) { | |
date.setMonth(date.getMonth() - 1); | |
this.removeChild(this.lastChild); | |
this.insertBefore(ScrollCalendar.renderElement(date), this.firstChild); | |
} else { // SCROLL_DOWN | |
date.setMonth(date.getMonth() + 1); | |
this.removeChild(this.firstChild); | |
this.appendChild(ScrollCalendar.renderElement(date)); | |
} | |
} | |
} | |
constructor() { | |
super(); | |
this.style.display = 'block'; | |
this.style.overflowY = 'scroll'; | |
this.render(); | |
} | |
} | |
customElements.define('scroll-calendar', ScrollCalendar); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment