63fd319509
Deploy / deploy (push) Successful in 1m19s
day-nav.ts's header always resolved via resolveDay(date) regardless of selected hour, so viewing Vespers/Compline on a day whose evening anticipates tomorrow's First Vespers (e.g. Aug 25, 2026: St. Louis's day, but St. Zephyrinus claims First Vespers per calendar/vespers.ts) still showed today's saint in the header while the hour's actual content had already switched to tomorrow's. Now uses resolveEveningDay for those two hours specifically. Also adds an explicit "First Vespers (of tomorrow)" / "Second Vespers (of today)" status line to the Vespers header, via new getVespersStatusLabel(), so the anticipation/commemoration result is visible rather than only inferable from which saint's name shows up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014axryJBrRswYh2niA7WCUc
58 lines
3.2 KiB
TypeScript
58 lines
3.2 KiB
TypeScript
import { getState, shiftDate, goToToday, addDays, todayIso } from '../app-state';
|
|
import { resolveDay } from '../calendar';
|
|
import { resolveEveningDay } from '../calendar/vespers';
|
|
import { getDayLabel, getVespersStatusLabel } from '../calendar/day-label';
|
|
import { urlFor } from '../router';
|
|
import { formatDateLong, renderBilingual } from './format';
|
|
|
|
/** Renders navigation plus the merged "when" header: the civil date/
|
|
* weekday and the liturgical day-being-celebrated, together in one place
|
|
* — previously the date lived here while the day-being-celebrated text
|
|
* was repeated separately inside every hour's own view. The day-being-
|
|
* celebrated text is hour-independent for the daytime hours (the same
|
|
* `LiturgicalDay` for every hour on a given date) but NOT for Vespers/
|
|
* Compline: those two can belong to *tomorrow's* identity instead (First
|
|
* Vespers anticipation — see `calendar/vespers.ts`'s `resolveEveningDay`),
|
|
* so this header must resolve through that function for those two hours
|
|
* specifically, or it shows the wrong saint (previously always used plain
|
|
* `resolveDay`, silently mismatched against what the hour itself was
|
|
* actually rendering). */
|
|
export function renderDayNav(container: HTMLElement): void {
|
|
const { date, selectedHour, languages } = getState();
|
|
const isEveningHour = selectedHour === 'vespers' || selectedHour === 'compline';
|
|
const day = isEveningHour ? resolveEveningDay(date) : resolveDay(date);
|
|
const dateLabel = formatDateLong(date);
|
|
const dayLabel = getDayLabel(day);
|
|
const vespersStatus = selectedHour === 'vespers' ? getVespersStatusLabel(day) : undefined;
|
|
const prevUrl = urlFor(addDays(date, -1), selectedHour, languages);
|
|
const nextUrl = urlFor(addDays(date, 1), selectedHour, languages);
|
|
const todayUrl = urlFor(todayIso(), selectedHour, languages);
|
|
container.innerHTML = `
|
|
<nav class="day-nav" aria-label="Day navigation">
|
|
<a href="${prevUrl}" class="day-nav-btn" data-action="prev" aria-label="Previous day">←</a>
|
|
<a href="${todayUrl}" class="day-nav-btn day-nav-today" data-action="today">Today</a>
|
|
<div class="day-nav-header">
|
|
${renderBilingual(dateLabel, languages, 'day-nav-date')}
|
|
${renderBilingual(dayLabel, languages, 'day-nav-label')}
|
|
${vespersStatus ? renderBilingual(vespersStatus, languages, 'day-nav-vespers-status') : ''}
|
|
</div>
|
|
<a href="${nextUrl}" class="day-nav-btn" data-action="next" aria-label="Next day">→</a>
|
|
</nav>
|
|
`;
|
|
|
|
const bindNav = (action: string, mutate: () => void): void => {
|
|
container.querySelector<HTMLAnchorElement>(`[data-action="${action}"]`)?.addEventListener('click', (event) => {
|
|
// Let modifier/middle clicks fall through to normal browser navigation
|
|
// (open in new tab, etc.) — only plain left-clicks are SPA-routed.
|
|
if (event.defaultPrevented || (event as MouseEvent).button !== 0 || (event as MouseEvent).metaKey || (event as MouseEvent).ctrlKey || (event as MouseEvent).shiftKey || (event as MouseEvent).altKey) {
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
mutate();
|
|
});
|
|
};
|
|
bindNav('prev', () => shiftDate(-1));
|
|
bindNav('next', () => shiftDate(1));
|
|
bindNav('today', () => goToToday());
|
|
}
|