Skip to content

Instantly share code, notes, and snippets.

@dladukedev
Created June 30, 2025 02:35
Show Gist options
  • Save dladukedev/7df7f497492b28810431674a2ee65e85 to your computer and use it in GitHub Desktop.
Save dladukedev/7df7f497492b28810431674a2ee65e85 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calendar</title>
<style>
* {
margin: 0;
padding: 0;
font-family: 'Arial';
box-sizing: border-box;
}
@media print {
.no-print {
display: none;
}
}
.calendar-header {
height: .5in;
}
body {
padding: .2in .5in;
}
#header {
font-size: .4in;
}
table,
th,
td {
border: 1px solid black;
}
table {
border-collapse: collapse;
}
th {
height: .2in;
}
td {
font-weight: bold;
padding: .05in;
width: 1.4in;
height: 1.2in;
vertical-align: top;
}
td.other-month {
color: darkgrey;
}
</style>
</head>
<body>
<div class="calendar-header">
<div class="month-year" id="header"></div>
</div>
<table id="calendar">
<tr class="day-header">
<th>Sunday</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
</tr>
<tbody id="calendarBody"></tbody>
</table>
<script>
const getCalendarMonthName = (calendar) => {
return new Date(calendar.year, calendar.month)
.toLocaleString('default', {month: 'long'});
}
const getEligibleDates = (calendar) => {
const firstOfMonth = new Date(calendar.year, calendar.month)
const dayOfStart = firstOfMonth.getDay()
const start = new Date(calendar.year, calendar.month, 1 - dayOfStart)
return [...new Array(42).keys()].map(offset => {
const date = new Date(start.getFullYear(), start.getMonth(), start.getDate() + offset)
return {
date: date.getDate(),
isCalendarMonth: date.getMonth() === calendar.month,
}
})
}
const removeExtraWeek = (dates) => {
const firstWeek = dates.slice(0, 7)
const lastWeek = dates.slice(-7)
const rest = dates.slice(7, -7)
const firstInMonthCount = firstWeek.filter(day => day.isCalendarMonth).length
const lastInMonthCount = lastWeek.filter(day => day.isCalendarMonth).length
return lastInMonthCount === 0 || firstInMonthCount > 3
? [...firstWeek, ...rest]
: [...rest, ...lastWeek]
}
const splitWeeks = (dates) => {
return [
dates.slice(0, 7),
dates.slice(7, 14),
dates.slice(14, 21),
dates.slice(21, 28),
dates.slice(28, 35),
]
}
const buildCalendarModel = (calendar) => {
const eligibleDates = getEligibleDates(calendar)
const dates = removeExtraWeek(eligibleDates)
const weeks = splitWeeks(dates)
return {
monthName: getCalendarMonthName(calendar),
year: calendar.year.toString(),
weeks,
}
}
const asDateHtml = (day) => {
const classes = day.isCalendarMonth ? 'date' : 'date other-month'
return `<td class="${classes}">${day.date}</td>`
}
const asWeekHtml = (week) => {
const weekHtml = week
.map(asDateHtml)
.join('')
return `<tr>${weekHtml}</tr>`
}
const buildCalendarHtml = (calendarModel) => {
const headerHtml = `${calendarModel.monthName} ${calendarModel.year}`
const weeksHtml = calendarModel.weeks
.map(asWeekHtml)
.join('')
return {
headerHtml,
weeksHtml,
}
}
const updateCalendar = (getCalendar, updateCalendarUi) => {
const calendar = getCalendar()
const calendarModel = buildCalendarModel(calendar)
const calendarHtml = buildCalendarHtml(calendarModel)
updateCalendarUi(calendarHtml)
}
const parseMonth = (month) => {
if (!month) return null
const parsedMonth = parseInt(month)
const isValid = !isNaN(parsedMonth) && parsedMonth <= 12 && parsedMonth >= 1
return isValid ? parsedMonth - 1 : null
}
const parseYear = (year) => {
if (!year) return null
const parsedYear = parseInt(year)
const isValid = !isNaN(parsedYear) && parsedYear >= 0
return isValid ? parsedYear : null
}
const getCalendarFromParams = () => {
const now = new Date()
const urlParams = new URLSearchParams(window.location.search);
const monthParam = urlParams.get('m');
const yearParam = urlParams.get('y');
const parsedMonth = parseMonth(monthParam)
const parsedYear = parseYear(yearParam)
const [month, year] = parsedMonth && parsedYear ? [parsedMonth, parsedYear] : [now.getMonth(), now.getFullYear()]
return {month, year}
}
const updateCalendarUi = (calendarHtml) => {
document.getElementById('header').innerHTML = calendarHtml.headerHtml
document.getElementById('calendarBody').innerHTML = calendarHtml.weeksHtml
}
updateCalendar(getCalendarFromParams, updateCalendarUi)
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment