diff --git a/src/constants/EventTypes.ts b/src/constants/EventTypes.ts
index 3134579..d51129d 100644
--- a/src/constants/EventTypes.ts
+++ b/src/constants/EventTypes.ts
@@ -13,6 +13,7 @@ export const EventTypes = {
CONFIG_UPDATE: 'calendar:configupdate',
CALENDAR_TYPE_CHANGED: 'calendar:calendartypechanged',
SELECTED_DATE_CHANGED: 'calendar:selecteddatechanged',
+ WORKWEEK_CHANGED: 'calendar:workweekchanged',
// View change events
VIEW_CHANGE: 'calendar:viewchange',
@@ -86,7 +87,7 @@ export const EventTypes = {
// Management events (legacy - prefer StateEvents)
REFRESH_REQUESTED: 'calendar:refreshrequested',
RESET_REQUESTED: 'calendar:resetrequested',
- CALENDAR_REFRESH_REQUESTED: 'calendar:refreshrequested',
+ CALENDAR_REFRESH_REQUESTED: 'calendar:calendarrefreshrequested',
CALENDAR_RESET: 'calendar:reset',
// System events
diff --git a/src/core/CalendarConfig.ts b/src/core/CalendarConfig.ts
index 7aeef1a..cef5e5c 100644
--- a/src/core/CalendarConfig.ts
+++ b/src/core/CalendarConfig.ts
@@ -35,6 +35,17 @@ interface DateViewSettings {
showAllDay: boolean; // Show all-day event row
}
+/**
+ * Work week configuration settings
+ */
+interface WorkWeekSettings {
+ id: string;
+ workDays: number[]; // [1,2,3,4,5] for mon-fri
+ dayNames: string[]; // ['Mon','Tue','Wed','Thu','Fri']
+ totalDays: number; // 5
+ firstWorkDay: number; // 1 = Monday
+}
+
/**
* View settings for resource-based calendar mode
*/
@@ -57,6 +68,7 @@ export class CalendarConfig {
private gridSettings: GridSettings;
private dateViewSettings: DateViewSettings;
private resourceViewSettings: ResourceViewSettings;
+ private currentWorkWeek: string = 'standard';
constructor() {
this.config = {
@@ -422,6 +434,83 @@ export class CalendarConfig {
date: date
});
}
+
+ /**
+ * Get work week presets
+ */
+ private getWorkWeekPresets(): { [key: string]: WorkWeekSettings } {
+ return {
+ 'standard': {
+ id: 'standard',
+ workDays: [1,2,3,4,5],
+ dayNames: ['Mon','Tue','Wed','Thu','Fri'],
+ totalDays: 5,
+ firstWorkDay: 1
+ },
+ 'compressed': {
+ id: 'compressed',
+ workDays: [1,2,3,4],
+ dayNames: ['Mon','Tue','Wed','Thu'],
+ totalDays: 4,
+ firstWorkDay: 1
+ },
+ 'midweek': {
+ id: 'midweek',
+ workDays: [3,4,5],
+ dayNames: ['Wed','Thu','Fri'],
+ totalDays: 3,
+ firstWorkDay: 3
+ },
+ 'weekend': {
+ id: 'weekend',
+ workDays: [6,0],
+ dayNames: ['Sat','Sun'],
+ totalDays: 2,
+ firstWorkDay: 6
+ },
+ 'fullweek': {
+ id: 'fullweek',
+ workDays: [0,1,2,3,4,5,6],
+ dayNames: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
+ totalDays: 7,
+ firstWorkDay: 0
+ }
+ };
+ }
+
+ /**
+ * Get current work week settings
+ */
+ getWorkWeekSettings(): WorkWeekSettings {
+ const presets = this.getWorkWeekPresets();
+ return presets[this.currentWorkWeek] || presets['standard'];
+ }
+
+ /**
+ * Set work week preset
+ */
+ setWorkWeek(workWeekId: string): void {
+ const presets = this.getWorkWeekPresets();
+ if (presets[workWeekId]) {
+ this.currentWorkWeek = workWeekId;
+
+ // Update dateViewSettings to match work week
+ this.dateViewSettings.weekDays = presets[workWeekId].totalDays;
+
+ // Emit work week change event
+ eventBus.emit(EventTypes.WORKWEEK_CHANGED, {
+ workWeekId: workWeekId,
+ settings: presets[workWeekId]
+ });
+ }
+ }
+
+ /**
+ * Get current work week ID
+ */
+ getCurrentWorkWeek(): string {
+ return this.currentWorkWeek;
+ }
}
// Create singleton instance
diff --git a/src/managers/CalendarManager.ts b/src/managers/CalendarManager.ts
index a19481c..66c0e7e 100644
--- a/src/managers/CalendarManager.ts
+++ b/src/managers/CalendarManager.ts
@@ -264,6 +264,13 @@ export class CalendarManager {
this.refresh();
});
+ // Lyt efter workweek changes
+ this.eventBus.on(EventTypes.WORKWEEK_CHANGED, (event: Event) => {
+ const customEvent = event as CustomEvent;
+ console.log('CalendarManager: Workweek changed to', customEvent.detail.workWeekId);
+ this.handleWorkweekChange();
+ });
+
// Lyt efter reset requests
this.eventBus.on(EventTypes.RESET_REQUESTED, () => {
this.reset();
@@ -281,7 +288,8 @@ export class CalendarManager {
nextDate.setDate(nextDate.getDate() + 1);
break;
case 'week':
- nextDate.setDate(nextDate.getDate() + 7);
+ const workWeekSettings = this.config.getWorkWeekSettings();
+ nextDate.setDate(nextDate.getDate() + 7); // Move to next calendar week regardless of work days
break;
case 'month':
nextDate.setMonth(nextDate.getMonth() + 1);
@@ -302,7 +310,8 @@ export class CalendarManager {
previousDate.setDate(previousDate.getDate() - 1);
break;
case 'week':
- previousDate.setDate(previousDate.getDate() - 7);
+ const workWeekSettings = this.config.getWorkWeekSettings();
+ previousDate.setDate(previousDate.getDate() - 7); // Move to previous calendar week regardless of work days
break;
case 'month':
previousDate.setMonth(previousDate.getMonth() - 1);
@@ -370,4 +379,42 @@ export class CalendarManager {
}
}
+ /**
+ * Handle workweek configuration changes
+ */
+ private handleWorkweekChange(): void {
+ console.log('CalendarManager: Handling workweek change - forcing full grid rebuild');
+
+ // Force a complete grid rebuild by clearing existing structure
+ const container = document.querySelector('swp-calendar-container');
+ if (container) {
+ container.innerHTML = ''; // Clear everything to force full rebuild
+ }
+
+ // Re-render the grid with new workweek settings (will now rebuild everything)
+ this.gridManager.render();
+
+ // Re-initialize scroll manager after grid rebuild
+ this.scrollManager.initialize();
+
+ // Re-render events in the new grid structure
+ this.rerenderEvents();
+ }
+
+ /**
+ * Re-render events after grid structure changes
+ */
+ private rerenderEvents(): void {
+ console.log('CalendarManager: Re-rendering events for new workweek');
+
+ // Get current period data to determine date range
+ const periodData = this.calculateCurrentPeriod();
+
+ // Trigger event rendering for the current date range
+ this.eventRenderer.renderEventsForDateRange(
+ periodData.startDate,
+ periodData.endDate
+ );
+ }
+
}
\ No newline at end of file
diff --git a/src/managers/NavigationManager.ts b/src/managers/NavigationManager.ts
index 9ec7b24..2208b42 100644
--- a/src/managers/NavigationManager.ts
+++ b/src/managers/NavigationManager.ts
@@ -2,6 +2,7 @@ import { IEventBus } from '../types/CalendarTypes.js';
import { DateUtils } from '../utils/DateUtils.js';
import { EventTypes } from '../constants/EventTypes.js';
import { NavigationRenderer } from '../renderers/NavigationRenderer.js';
+import { calendarConfig } from '../core/CalendarConfig.js';
/**
* NavigationManager handles calendar navigation (prev/next/today buttons)
@@ -17,7 +18,7 @@ export class NavigationManager {
constructor(eventBus: IEventBus) {
console.log('🧠NavigationManager: Constructor called');
this.eventBus = eventBus;
- this.navigationRenderer = new NavigationRenderer(eventBus);
+ this.navigationRenderer = new NavigationRenderer(eventBus, calendarConfig);
this.currentWeek = DateUtils.getWeekStart(new Date(), 0); // Sunday start like POC
this.targetWeek = new Date(this.currentWeek);
this.init();
diff --git a/src/managers/ViewManager.ts b/src/managers/ViewManager.ts
index a121e51..1f9c8f3 100644
--- a/src/managers/ViewManager.ts
+++ b/src/managers/ViewManager.ts
@@ -33,6 +33,9 @@ export class ViewManager {
// Setup view button handlers
this.setupViewButtonHandlers();
+
+ // Setup workweek preset button handlers
+ this.setupWorkweekButtonHandlers();
}
private setupViewButtonHandlers(): void {
@@ -48,8 +51,22 @@ export class ViewManager {
});
}
+ private setupWorkweekButtonHandlers(): void {
+ const workweekButtons = document.querySelectorAll('swp-preset-button[data-workweek]');
+ workweekButtons.forEach(button => {
+ button.addEventListener('click', (event) => {
+ event.preventDefault();
+ const workweekId = button.getAttribute('data-workweek');
+ if (workweekId) {
+ this.changeWorkweek(workweekId);
+ }
+ });
+ });
+ }
+
private initializeView(): void {
this.updateViewButtons();
+ this.updateWorkweekButtons();
this.eventBus.emit(EventTypes.VIEW_RENDERED, {
view: this.currentView
@@ -72,6 +89,18 @@ export class ViewManager {
});
}
+ private changeWorkweek(workweekId: string): void {
+ console.log(`ViewManager: Changing workweek to ${workweekId}`);
+
+ // Update the calendar config
+ calendarConfig.setWorkWeek(workweekId);
+
+ // Update button states
+ this.updateWorkweekButtons();
+
+ // Trigger a calendar refresh to apply the new workweek
+ this.eventBus.emit(EventTypes.REFRESH_REQUESTED);
+ }
private updateViewButtons(): void {
const viewButtons = document.querySelectorAll('swp-view-button[data-view]');
@@ -85,6 +114,20 @@ export class ViewManager {
});
}
+ private updateWorkweekButtons(): void {
+ const currentWorkweek = calendarConfig.getCurrentWorkWeek();
+ const workweekButtons = document.querySelectorAll('swp-preset-button[data-workweek]');
+
+ workweekButtons.forEach(button => {
+ const buttonWorkweek = button.getAttribute('data-workweek');
+ if (buttonWorkweek === currentWorkweek) {
+ button.setAttribute('data-active', 'true');
+ } else {
+ button.removeAttribute('data-active');
+ }
+ });
+ }
+
private refreshCurrentView(): void {
this.eventBus.emit(EventTypes.VIEW_RENDERED, {
view: this.currentView
diff --git a/src/renderers/ColumnRenderer.ts b/src/renderers/ColumnRenderer.ts
index 4fdf151..a6e55f9 100644
--- a/src/renderers/ColumnRenderer.ts
+++ b/src/renderers/ColumnRenderer.ts
@@ -26,7 +26,7 @@ export class DateColumnRenderer implements ColumnRenderer {
render(columnContainer: HTMLElement, context: ColumnRenderContext): void {
const { currentWeek, config } = context;
- const dates = this.getWeekDates(currentWeek);
+ const dates = this.getWeekDates(currentWeek, config);
const dateSettings = config.getDateViewSettings();
const daysToShow = dates.slice(0, dateSettings.weekDays);
@@ -43,13 +43,20 @@ export class DateColumnRenderer implements ColumnRenderer {
});
}
- private getWeekDates(weekStart: Date): Date[] {
+ private getWeekDates(weekStart: Date, config: CalendarConfig): Date[] {
const dates: Date[] = [];
- for (let i = 0; i < 7; i++) {
+ const workWeekSettings = config.getWorkWeekSettings();
+
+ // Calculate dates based on actual work days (e.g., [1,2,3,4] for Mon-Thu)
+ workWeekSettings.workDays.forEach(dayOfWeek => {
const date = new Date(weekStart);
- date.setDate(weekStart.getDate() + i);
+ // Set to the start of the week (Sunday = 0)
+ date.setDate(weekStart.getDate() - weekStart.getDay());
+ // Add the specific day of week
+ date.setDate(date.getDate() + dayOfWeek);
dates.push(date);
- }
+ });
+
return dates;
}
diff --git a/src/renderers/GridStyleManager.ts b/src/renderers/GridStyleManager.ts
index c6cd417..44fb3df 100644
--- a/src/renderers/GridStyleManager.ts
+++ b/src/renderers/GridStyleManager.ts
@@ -60,19 +60,21 @@ export class GridStyleManager {
return resourceData.resources.length;
} else if (calendarType === 'date') {
const dateSettings = this.config.getDateViewSettings();
+ const workWeekSettings = this.config.getWorkWeekSettings();
+
switch (dateSettings.period) {
case 'day':
return 1;
case 'week':
- return dateSettings.weekDays;
+ return workWeekSettings.totalDays;
case 'month':
- return 7;
+ return workWeekSettings.totalDays; // Use work week for month view too
default:
- return dateSettings.weekDays;
+ return workWeekSettings.totalDays;
}
}
- return 7; // Default
+ return this.config.getWorkWeekSettings().totalDays; // Default to work week
}
/**
diff --git a/src/renderers/HeaderRenderer.ts b/src/renderers/HeaderRenderer.ts
index f12f06b..cf2d734 100644
--- a/src/renderers/HeaderRenderer.ts
+++ b/src/renderers/HeaderRenderer.ts
@@ -27,18 +27,19 @@ export class DateHeaderRenderer implements HeaderRenderer {
render(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
const { currentWeek, config, allDayEvents = [] } = context;
- const dates = this.getWeekDates(currentWeek);
+ const dates = this.getWeekDates(currentWeek, config);
const weekDays = config.get('weekDays');
const daysToShow = dates.slice(0, weekDays);
- daysToShow.forEach((date) => {
+ const workWeekSettings = config.getWorkWeekSettings();
+ daysToShow.forEach((date, index) => {
const header = document.createElement('swp-day-header');
if (this.isToday(date)) {
(header as any).dataset.today = 'true';
}
header.innerHTML = `
- ${this.getDayName(date)}
+ ${workWeekSettings.dayNames[index]}
${date.getDate()}
`;
(header as any).dataset.date = this.formatDate(date);
@@ -53,7 +54,7 @@ export class DateHeaderRenderer implements HeaderRenderer {
private renderAllDayEvents(calendarHeader: HTMLElement, context: HeaderRenderContext): void {
const { currentWeek, config, allDayEvents = [] } = context;
- const dates = this.getWeekDates(currentWeek);
+ const dates = this.getWeekDates(currentWeek, config);
const weekDays = config.get('weekDays');
const daysToShow = dates.slice(0, weekDays);
@@ -101,13 +102,20 @@ export class DateHeaderRenderer implements HeaderRenderer {
});
}
- private getWeekDates(weekStart: Date): Date[] {
+ private getWeekDates(weekStart: Date, config: CalendarConfig): Date[] {
const dates: Date[] = [];
- for (let i = 0; i < 7; i++) {
+ const workWeekSettings = config.getWorkWeekSettings();
+
+ // Calculate dates based on actual work days (e.g., [1,2,3,4] for Mon-Thu)
+ workWeekSettings.workDays.forEach(dayOfWeek => {
const date = new Date(weekStart);
- date.setDate(weekStart.getDate() + i);
+ // Set to the start of the week (Sunday = 0)
+ date.setDate(weekStart.getDate() - weekStart.getDay());
+ // Add the specific day of week
+ date.setDate(date.getDate() + dayOfWeek);
dates.push(date);
- }
+ });
+
return dates;
}
@@ -120,10 +128,6 @@ export class DateHeaderRenderer implements HeaderRenderer {
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}
- private getDayName(date: Date): string {
- const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
- return days[date.getDay()];
- }
}
/**
diff --git a/src/renderers/NavigationRenderer.ts b/src/renderers/NavigationRenderer.ts
index 82ef28a..bc22ce3 100644
--- a/src/renderers/NavigationRenderer.ts
+++ b/src/renderers/NavigationRenderer.ts
@@ -1,6 +1,7 @@
import { IEventBus } from '../types/CalendarTypes';
import { EventTypes } from '../constants/EventTypes';
import { DateUtils } from '../utils/DateUtils';
+import { CalendarConfig } from '../core/CalendarConfig';
/**
* NavigationRenderer - Handles DOM rendering for navigation containers
@@ -8,9 +9,11 @@ import { DateUtils } from '../utils/DateUtils';
*/
export class NavigationRenderer {
private eventBus: IEventBus;
+ private config: CalendarConfig;
- constructor(eventBus: IEventBus) {
+ constructor(eventBus: IEventBus, config: CalendarConfig) {
this.eventBus = eventBus;
+ this.config = config;
this.setupEventListeners();
}
@@ -97,10 +100,13 @@ export class NavigationRenderer {
dayColumns.innerHTML = '';
// Render headers for target week
- const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
- for (let i = 0; i < 7; i++) {
+ const workWeekSettings = this.config.getWorkWeekSettings();
+ workWeekSettings.workDays.forEach((dayOfWeek, i) => {
const date = new Date(weekStart);
- date.setDate(date.getDate() + i);
+ // Set to the start of the week (Sunday = 0)
+ date.setDate(weekStart.getDate() - weekStart.getDay());
+ // Add the specific day of week
+ date.setDate(date.getDate() + dayOfWeek);
const headerElement = document.createElement('swp-day-header');
if (this.isToday(date)) {
@@ -108,26 +114,29 @@ export class NavigationRenderer {
}
headerElement.innerHTML = `
- ${days[date.getDay()]}
+ ${workWeekSettings.dayNames[i]}
${date.getDate()}
`;
headerElement.dataset.date = this.formatDate(date);
header.appendChild(headerElement);
- }
+ });
// Render day columns for target week
- for (let i = 0; i < 7; i++) {
+ workWeekSettings.workDays.forEach(dayOfWeek => {
const column = document.createElement('swp-day-column');
const date = new Date(weekStart);
- date.setDate(date.getDate() + i);
+ // Set to the start of the week (Sunday = 0)
+ date.setDate(weekStart.getDate() - weekStart.getDay());
+ // Add the specific day of week
+ date.setDate(date.getDate() + dayOfWeek);
column.dataset.date = this.formatDate(date);
const eventsLayer = document.createElement('swp-events-layer');
column.appendChild(eventsLayer);
dayColumns.appendChild(column);
- }
+ });
}
/**
diff --git a/wwwroot/css/calendar-components-css.css b/wwwroot/css/calendar-components-css.css
index a0b6668..df8ff1c 100644
--- a/wwwroot/css/calendar-components-css.css
+++ b/wwwroot/css/calendar-components-css.css
@@ -87,6 +87,44 @@ swp-view-button {
}
}
+/* Workweek Presets */
+swp-workweek-presets {
+ display: flex;
+ background: var(--color-surface);
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+ overflow: hidden;
+ margin-left: 16px;
+}
+
+swp-preset-button {
+ padding: 6px 12px;
+ border: none;
+ background: transparent;
+ cursor: pointer;
+ font-size: 0.75rem;
+ font-weight: 500;
+ transition: all var(--transition-fast);
+ position: relative;
+ color: var(--color-text-secondary);
+
+ &:not(:last-child) {
+ border-right: 1px solid var(--color-border);
+ }
+
+
+ &[data-active="true"] {
+ background: var(--color-primary);
+ color: white;
+ font-weight: 600;
+ }
+
+ &[disabled] {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
/* Search container */
swp-search-container {
margin-left: auto;
diff --git a/wwwroot/index.html b/wwwroot/index.html
index ed4a102..2219578 100644
--- a/wwwroot/index.html
+++ b/wwwroot/index.html
@@ -48,6 +48,14 @@
Week
Month
+
+
+ Mon-Fri
+ Mon-Thu
+ Wed-Fri
+ Sat-Sun
+ 7 Days
+