@@ -694,6 +1058,12 @@
event.target.classList.add('active');
if (tabId === 'calendar') renderCalendar();
+ if (tabId === 'overlap') {
+ if (!overlapState.selectedDate) {
+ overlapState.selectedDate = new Date();
+ }
+ renderOverlapView();
+ }
}
// Single date converter
@@ -868,6 +1238,376 @@
document.getElementById('ifc-day').addEventListener('input', updateGregorianResult);
document.getElementById('calendar-year').addEventListener('change', renderCalendar);
+ // ==================== VISUAL OVERLAP FUNCTIONS ====================
+
+ let overlapState = {
+ zoom: 'month', // 'month', 'week', 'day'
+ centerDate: new Date(), // Current center date for navigation
+ selectedDate: null // Currently selected date for detail view
+ };
+
+ const GREG_MONTHS = ['January', 'February', 'March', 'April', 'May', 'June',
+ 'July', 'August', 'September', 'October', 'November', 'December'];
+ const WEEKDAYS_SHORT = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
+
+ function setOverlapZoom(zoom) {
+ overlapState.zoom = zoom;
+ document.querySelectorAll('.zoom-btn').forEach(btn => btn.classList.remove('active'));
+ document.getElementById(`zoom-${zoom}`).classList.add('active');
+ renderOverlapView();
+ }
+
+ function navigateOverlap(delta) {
+ const d = overlapState.centerDate;
+ switch (overlapState.zoom) {
+ case 'month':
+ d.setMonth(d.getMonth() + delta);
+ break;
+ case 'week':
+ d.setDate(d.getDate() + (delta * 7));
+ break;
+ case 'day':
+ d.setDate(d.getDate() + delta);
+ break;
+ }
+ renderOverlapView();
+ }
+
+ function overlapToToday() {
+ overlapState.centerDate = new Date();
+ overlapState.selectedDate = new Date();
+ renderOverlapView();
+ }
+
+ function selectOverlapDate(dateStr) {
+ overlapState.selectedDate = new Date(dateStr + 'T12:00:00');
+ renderOverlapView();
+ }
+
+ function formatGregorianShort(date) {
+ return `${GREG_MONTHS[date.getMonth()].substring(0, 3)} ${date.getDate()}`;
+ }
+
+ function formatIFCShort(ifc) {
+ if (ifc.special) return ifc.special;
+ return `${ifc.monthName.substring(0, 3)} ${ifc.day}`;
+ }
+
+ function renderOverlapView() {
+ const container = document.getElementById('overlap-view');
+ const dateLabel = document.getElementById('overlap-current-date');
+
+ switch (overlapState.zoom) {
+ case 'month':
+ renderMonthOverlap(container, dateLabel);
+ break;
+ case 'week':
+ renderWeekOverlap(container, dateLabel);
+ break;
+ case 'day':
+ renderDayOverlap(container, dateLabel);
+ break;
+ }
+ }
+
+ function renderMonthOverlap(container, dateLabel) {
+ const center = overlapState.centerDate;
+ const year = center.getFullYear();
+ const month = center.getMonth();
+ const today = new Date();
+
+ dateLabel.textContent = `${GREG_MONTHS[month]} ${year}`;
+
+ // Get first and last day of the Gregorian month
+ const firstDay = new Date(year, month, 1);
+ const lastDay = new Date(year, month + 1, 0);
+ const startPadding = firstDay.getDay(); // Day of week (0-6)
+
+ let html = `
+
+ ${WEEKDAYS_SHORT.map(d => `${d}`).join('')}
+
+
+ `;
+
+ // Add padding for first week
+ for (let i = 0; i < startPadding; i++) {
+ html += '';
+ }
+
+ // Add each day of the month
+ for (let day = 1; day <= lastDay.getDate(); day++) {
+ const date = new Date(year, month, day);
+ const ifc = gregorianToIFC(date);
+ const isToday = date.toDateString() === today.toDateString();
+ const isSelected = overlapState.selectedDate &&
+ date.toDateString() === overlapState.selectedDate.toDateString();
+ const dateStr = date.toISOString().split('T')[0];
+
+ const ifcDisplay = ifc.special
+ ? `${ifc.special}`
+ : `${ifc.monthName.substring(0, 3)} ${ifc.day}`;
+
+ html += `
+
+
${GREG_MONTHS[month].substring(0, 3)} ${day}
+
+
${ifcDisplay}
+
+ `;
+ }
+
+ html += '
';
+
+ // Add day detail if a date is selected
+ if (overlapState.selectedDate) {
+ html += renderDayDetail(overlapState.selectedDate);
+ }
+
+ container.innerHTML = html;
+ }
+
+ function renderWeekOverlap(container, dateLabel) {
+ const center = overlapState.centerDate;
+ const today = new Date();
+
+ // Get the week centered on the current date (3 days before, selected, 3 days after)
+ const days = [];
+ for (let i = -3; i <= 3; i++) {
+ const d = new Date(center);
+ d.setDate(center.getDate() + i);
+ days.push(d);
+ }
+
+ dateLabel.textContent = `Week of ${formatGregorianShort(days[3])}`;
+
+ let html = `
+