Last active
February 26, 2022 13:39
-
-
Save art-solopov/bb2bfd530e4f2b3b6c2256727b933cb0 to your computer and use it in GitHub Desktop.
A very simple calendar widget for Stimulus.JS
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
import moment from 'moment' | |
import { Controller } from 'stimulus' | |
const TOGGLE_BUTTON_TEMPLATE = ` | |
<button data-target="cal-grid.toggleButton" data-action="cal-grid#toggleWidget"></button> | |
` | |
const DROPDOWN_TEMPLATE = ` | |
<div class="cal-grid--dropdown" data-target="cal-grid.dropdown"> | |
<div> | |
<button data-action="cal-grid#prevMonth"><</button> | |
<span data-target="cal-grid.currMonth"></span> | |
<button data-action="cal-grid#nextMonth">></button> | |
</div> | |
<div class="cal-grid--grid" data-target="cal-grid.grid"> | |
</div> | |
</div> | |
` | |
const CELL_TEMPLATE = ` | |
<a href="#" class="cal-grid--cell" role="button" data-action="click->cal-grid#setDate"></a> | |
` | |
class CalGridController extends Controller { | |
static targets = ['input', 'toggleButton', 'dropdown', 'grid', 'currMonth'] | |
connect () { | |
this.element.classList.add('cal-grid') | |
let tmpEl = document.createElement('div') | |
tmpEl.innerHTML = TOGGLE_BUTTON_TEMPLATE | |
this.element.appendChild(tmpEl.firstElementChild) | |
tmpEl.innerHTML = DROPDOWN_TEMPLATE | |
this.element.appendChild(tmpEl.firstElementChild) | |
this.hideWidget() | |
this.data.set('month', moment().date(1).format('YYYY-MM-DD')) | |
this.makeCalendar() | |
} | |
toggleWidget () { | |
if (this.element.dataset.widgetState == 'opened') { this.hideWidget(); } | |
else { this.showWidget() } | |
} | |
showWidget () { | |
this.toggleButtonTarget.innerText = 'Close' | |
this.element.dataset.widgetState = 'opened' | |
this.dropdownTarget.classList.add('show') | |
} | |
hideWidget () { | |
this.toggleButtonTarget.innerText = 'Open' | |
this.element.dataset.widgetState = 'closed' | |
this.dropdownTarget.classList.remove('show') | |
} | |
prevMonth () { | |
this.currMoment = this.currMoment.add(-1, 'month') | |
this.makeCalendar() | |
} | |
nextMonth () { | |
this.currMoment = this.currMoment.add(1, 'month') | |
this.makeCalendar() | |
} | |
makeCalendar() { | |
let d = this.currMoment | |
this.currMonthTarget.innerText = d.format('MMM YYYY') | |
this.gridTarget.innerHTML = '' | |
this.gridTarget.style.setProperty('--month-offset', d.isoWeekday() - 1) | |
for(let i = 1; i <= d.daysInMonth(); i++) { | |
let tmpEl = document.createElement('div') | |
tmpEl.innerHTML = CELL_TEMPLATE | |
let btn = tmpEl.firstElementChild | |
btn.dataset.date = d.date(i).format('YYYY-MM-DD') | |
btn.innerText = i | |
this.gridTarget.appendChild(btn) | |
} | |
} | |
setDate(e) { | |
e.preventDefault(); | |
let date = e.target.dataset.date | |
this.inputTarget.value = date | |
} | |
get currMoment () { | |
return moment(this.data.get('month')) | |
} | |
set currMoment (m) { | |
if (moment.isMoment(m)) this.data.set('month', m.format('YYYY-MM-DD')) | |
else this.currMoment = moment(m) | |
} | |
} | |
export default CalGridController |
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
.form-field { | |
padding: 0.5em; | |
width: 30em; | |
display: flex; | |
flex-flow: row nowrap; | |
& > input { | |
flex: 0 1 100%; | |
} | |
} | |
.cal-grid { | |
position: relative; | |
&--dropdown { | |
position: absolute; | |
top: 100%; | |
right: 0; | |
display: none; | |
padding: 0.25em; | |
border: 1px dotted #333; | |
&.show { | |
display: block; | |
} | |
} | |
&--grid { | |
display: grid; | |
grid-template-columns: repeat(7, 4em); | |
&::before { | |
content: '\00A0'; | |
grid-area: 1 / 1 / 1 / span var(--month-offset) | |
} | |
} | |
&--cell { | |
text-align: right; | |
padding: 0.5em; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
oh excellent, I think I'll be trying this.