Refactor calendar navigation with flexible day offsets

Improves date navigation by introducing dynamic period-based offsets for calendar views

Replaces week-based navigation with more flexible day offsets that support:
- Single-day and multi-day navigation
- Configurable work week presets with different period lengths
- More granular control over date range selection

Adds support for dynamic navigation periods through workweek preset configuration
This commit is contained in:
Janus C. H. Knudsen 2025-12-18 00:11:45 +01:00
parent 863b433eba
commit fa2eb66fb2
5 changed files with 526 additions and 43 deletions

View file

@ -24,7 +24,7 @@ import {
export class CalendarApp {
private animator!: NavigationAnimator;
private container!: HTMLElement;
private weekOffset = 0;
private dayOffset = 0;
private currentViewId = 'simple';
private workweekPreset: IWorkweekPreset | null = null;
private groupingOverrides: Map<string, string[]> = new Map();
@ -126,13 +126,15 @@ export class CalendarApp {
}
private async handleNavigatePrev(): Promise<void> {
this.weekOffset--;
const step = this.workweekPreset?.periodDays ?? 7;
this.dayOffset -= step;
await this.animator.slide('right', () => this.render());
this.emitStatus('rendered', { viewId: this.currentViewId });
}
private async handleNavigateNext(): Promise<void> {
this.weekOffset++;
const step = this.workweekPreset?.periodDays ?? 7;
this.dayOffset += step;
await this.animator.slide('left', () => this.render());
this.emitStatus('rendered', { viewId: this.currentViewId });
}
@ -159,11 +161,15 @@ export class CalendarApp {
return;
}
// Populate date values based on workweek and offset
// Populate date values based on workweek preset and day offset
const workDays = this.workweekPreset?.workDays || [1, 2, 3, 4, 5];
const dates = this.currentViewId === 'day'
? this.dateService.getWeekDates(this.weekOffset, 1)
: this.dateService.getWorkWeekDates(this.weekOffset, workDays);
const periodDays = this.workweekPreset?.periodDays ?? 7;
// For single-day navigation (periodDays=1), show consecutive days from offset
// For week navigation (periodDays=7), show workDays from the week containing offset
const dates = periodDays === 1
? this.dateService.getDatesFromOffset(this.dayOffset, workDays.length)
: this.dateService.getWorkDaysFromOffset(this.dayOffset, workDays);
// Clone config and apply overrides
const viewConfig: ViewConfig = {

View file

@ -41,21 +41,30 @@ export class DateService {
return new Intl.DateTimeFormat(this.config.locale, { weekday: format }).format(date);
}
getWeekDates(offset = 0, days = 7): string[] {
const monday = this.baseDate.startOf('week').add(1, 'day').add(offset, 'week');
return Array.from({ length: days }, (_, i) =>
monday.add(i, 'day').format('YYYY-MM-DD')
/**
* Get dates starting from a day offset
* @param dayOffset - Day offset from base date
* @param count - Number of consecutive days to return
* @returns Array of date strings in YYYY-MM-DD format
*/
getDatesFromOffset(dayOffset: number, count: number): string[] {
const startDate = this.baseDate.add(dayOffset, 'day');
return Array.from({ length: count }, (_, i) =>
startDate.add(i, 'day').format('YYYY-MM-DD')
);
}
/**
* Get dates for specific weekdays within a week
* @param offset - Week offset from base date (0 = current week)
* Get specific weekdays from the week containing the offset date
* @param dayOffset - Day offset from base date
* @param workDays - Array of ISO weekday numbers (1=Monday, 7=Sunday)
* @returns Array of date strings in YYYY-MM-DD format
*/
getWorkWeekDates(offset: number, workDays: number[]): string[] {
const monday = this.baseDate.startOf('week').add(1, 'day').add(offset, 'week');
getWorkDaysFromOffset(dayOffset: number, workDays: number[]): string[] {
// Get the date at offset, then find its week's Monday
const targetDate = this.baseDate.add(dayOffset, 'day');
const monday = targetDate.startOf('week').add(1, 'day');
return workDays.map(isoDay => {
// ISO: 1=Monday, 7=Sunday → days from Monday: 0-6
const daysFromMonday = isoDay === 7 ? 6 : isoDay - 1;
@ -63,6 +72,15 @@ export class DateService {
});
}
// Legacy methods for backwards compatibility
getWeekDates(weekOffset = 0, days = 7): string[] {
return this.getDatesFromOffset(weekOffset * 7, days);
}
getWorkWeekDates(weekOffset: number, workDays: number[]): string[] {
return this.getWorkDaysFromOffset(weekOffset * 7, workDays);
}
// ============================================
// FORMATTING
// ============================================

View file

@ -17,6 +17,7 @@ export interface IWorkweekPreset {
id: string;
workDays: number[];
label: string;
periodDays: number; // Navigation step in days (1 = day, 7 = week)
}
/**