kenat
Version:
A JavaScript library for the Ethiopian calendar with date and time support.
313 lines (274 loc) • 10.7 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kenat Full Year Calendar</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
text-align: center;
background-color: #f9f9f9;
padding: 1rem;
color: #333;
}
h1,
h2 {
color: #111;
}
.year-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 1.5rem;
max-width: 1400px;
margin: 1rem auto;
}
.month-card {
border: 1px solid #e0e0e0;
border-radius: 10px;
padding: 1rem;
background-color: #fff;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.month-card h3 {
margin-top: 0;
font-size: 1rem;
}
table {
border-collapse: collapse;
width: 100%;
}
th,
td {
border: 1px solid #f0f0f0;
padding: 0.3rem;
height: 35px;
text-align: center;
font-size: 0.8rem;
}
th {
background-color: #f7f7f7;
font-weight: 600;
font-size: 0.75rem;
}
.today {
background-color: #fffde7;
border: 1px solid #ffc107;
font-weight: bold;
}
.holiday {
background-color: #e3f2fd;
cursor: pointer;
}
.holiday:hover {
background-color: #bbdefb;
}
.main-controls {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
margin: 1.5rem 0;
align-items: center;
}
.filter-controls {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
justify-content: center;
margin-bottom: 1.5rem;
background-color: #fff;
padding: 1rem;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.filter-controls label {
font-size: 0.9rem;
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
}
button {
padding: 0.6rem 1.2rem;
font-size: 0.9rem;
cursor: pointer;
border-radius: 6px;
border: 1px solid #ccc;
background-color: #fff;
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 25px;
border-radius: 10px;
width: 90%;
max-width: 500px;
text-align: left;
position: relative;
}
.modal-close {
color: #aaa;
position: absolute;
top: 10px;
right: 20px;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
</style>
</head>
<body>
<div id="calendar-container"></div>
<div id="holidayModal" class="modal">
<div class="modal-content">
<span class="modal-close">×</span>
<div id="modalBody"></div>
</div>
</div>
<script type="module">
// FIX: Correctly import Kenat as the default export
import Kenat, { HolidayTags } from '../../src/index.js';
import { toGeez, toArabic } from '../../src/geezConverter.js';
let useGeez = false;
let weekdayLang = 'amharic';
let weekStart = 1;
let currentYear = new Kenat().getEthiopian().year;
let holidayFilter = null; // Start with no filter
const container = document.getElementById('calendar-container');
const modal = document.getElementById('holidayModal');
const modalBody = document.getElementById('modalBody');
const closeModal = document.querySelector('.modal-close');
function showHolidayModal(holidays) {
let content = '';
holidays.forEach((h, index) => {
content += `<h3>${h.name}</h3><p>${h.description}</p>`;
if (index < holidays.length - 1) content += '<hr>';
});
modalBody.innerHTML = content;
modal.style.display = 'flex';
}
closeModal.onclick = () => { modal.style.display = 'none'; };
window.onclick = (event) => { if (event.target == modal) modal.style.display = 'none'; };
function renderFullYearCalendar(year) {
currentYear = year;
// Pass the holidayFilter to getYearCalendar
const yearCalendar = Kenat.getYearCalendar(year, { useGeez, weekdayLang, weekStart, holidayFilter });
const displayYear = useGeez ? toGeez(year) : year;
let html = `<div style="text-align: center;">
<h2>📅 Ethiopian Calendar ${displayYear}</h2>
<div class="main-controls">
<button id="prevYear">⬅️ Prev Year</button>
<div style="display: flex; gap: 10px;">
<button id="toggleGeez">Geez (${useGeez ? 'ON' : 'OFF'})</button>
<button id="toggleLang">Lang (${weekdayLang})</button>
<button id="toggleWeekStart">Start (${weekStart === 1 ? 'Mon' : 'Sun'})</button>
</div>
<button id="nextYear">Next Year ➡️</button>
</div>
<div class="filter-controls" id="filterControls"></div>
</div>`;
html += `<div class="year-grid">`;
yearCalendar.forEach(month => {
const headers = (weekdayLang === 'english') ? month.headers.map(h => h.substring(0, 3)) : month.headers;
html += `
<div class="month-card">
<h3>${month.monthName}</h3>
<table>
<thead><tr>${headers.map(h => `<th>${h}</th>`).join('')}</tr></thead>
<tbody>
`;
for (let i = 0; i < month.days.length; i += 7) {
html += '<tr>';
for (let j = 0; j < 7; j++) {
const item = month.days[i + j];
if (!item) {
html += '<td></td>';
} else {
const isToday = item.isToday ? 'today' : '';
const isHoliday = item.holidays.length > 0 ? 'holiday' : '';
const holidayAttr = isHoliday ? `data-holidays='${JSON.stringify(item.holidays)}'` : '';
html += `<td class="${isToday} ${isHoliday}" ${holidayAttr}><strong>${item.ethiopian.day}</strong></td>`;
}
}
html += '</tr>';
}
html += `</tbody></table></div>`;
});
html += `</div>`;
container.innerHTML = html;
renderFilterControls();
attachEventListeners();
}
function renderFilterControls() {
const controlsContainer = document.getElementById('filterControls');
let controlsHtml = `<label><input type="checkbox" name="holidayTag" value="all" ${!holidayFilter ? 'checked' : ''}> All</label>`;
for (const key in HolidayTags) {
const value = HolidayTags[key];
const isChecked = holidayFilter && holidayFilter.includes(value);
controlsHtml += `<label><input type="checkbox" name="holidayTag" value="${value}" ${isChecked ? 'checked' : ''}> ${value}</label>`;
}
controlsContainer.innerHTML = controlsHtml;
}
function attachEventListeners() {
document.getElementById('prevYear').onclick = () => rerender(currentYear - 1);
document.getElementById('nextYear').onclick = () => rerender(currentYear + 1);
document.getElementById('toggleGeez').onclick = () => { useGeez = !useGeez; rerender(); };
document.getElementById('toggleLang').onclick = () => { weekdayLang = weekdayLang === 'amharic' ? 'english' : 'amharic'; rerender(); };
document.getElementById('toggleWeekStart').onclick = () => { weekStart = weekStart === 1 ? 0 : 1; rerender(); };
document.querySelectorAll('.holiday').forEach(cell => {
cell.onclick = () => {
const holidays = JSON.parse(cell.getAttribute('data-holidays'));
showHolidayModal(holidays);
};
});
// Improved checkbox logic
const allCheckbox = document.querySelector('input[name="holidayTag"][value="all"]');
const otherCheckboxes = document.querySelectorAll('input[name="holidayTag"]:not([value="all"])');
const updateFilter = () => {
const checkedValues = Array.from(otherCheckboxes)
.filter(i => i.checked)
.map(i => i.value);
if (checkedValues.length === 0) {
allCheckbox.checked = true;
holidayFilter = null;
} else {
allCheckbox.checked = false;
holidayFilter = checkedValues;
}
rerender();
};
allCheckbox.onchange = () => {
if (allCheckbox.checked) {
otherCheckboxes.forEach(cb => cb.checked = false);
holidayFilter = null;
rerender();
} else {
allCheckbox.checked = true;
}
};
otherCheckboxes.forEach(checkbox => {
checkbox.onchange = updateFilter;
});
}
function rerender(year = currentYear) {
renderFullYearCalendar(year);
}
rerender();
</script>
</body>
</html>