WIP on master
This commit is contained in:
parent
b6ab1ff50e
commit
80aaab46f2
25 changed files with 6291 additions and 927 deletions
67
src/index.ts
67
src/index.ts
|
|
@ -21,6 +21,10 @@ import { DragHoverManager } from './managers/DragHoverManager';
|
|||
import { HeaderManager } from './managers/HeaderManager';
|
||||
import { ConfigManager } from './managers/ConfigManager';
|
||||
|
||||
// Import repositories
|
||||
import { IEventRepository } from './repositories/IEventRepository';
|
||||
import { MockEventRepository } from './repositories/MockEventRepository';
|
||||
|
||||
// Import renderers
|
||||
import { DateHeaderRenderer, type IHeaderRenderer } from './renderers/DateHeaderRenderer';
|
||||
import { DateColumnRenderer, type ColumnRenderer } from './renderers/ColumnRenderer';
|
||||
|
|
@ -35,7 +39,6 @@ import { TimeFormatter } from './utils/TimeFormatter';
|
|||
import { PositionUtils } from './utils/PositionUtils';
|
||||
import { AllDayLayoutEngine } from './utils/AllDayLayoutEngine';
|
||||
import { WorkHoursManager } from './managers/WorkHoursManager';
|
||||
import { GridStyleManager } from './renderers/GridStyleManager';
|
||||
import { EventStackManager } from './managers/EventStackManager';
|
||||
import { EventLayoutCoordinator } from './managers/EventLayoutCoordinator';
|
||||
|
||||
|
|
@ -81,50 +84,53 @@ async function initializeCalendar(): Promise<void> {
|
|||
builder.registerInstance(CalendarConfig).as<CalendarConfig>();
|
||||
|
||||
// Register ConfigManager for event-driven config updates
|
||||
builder.registerType(ConfigManager).as<ConfigManager>().singleInstance();
|
||||
builder.registerType(ConfigManager).as<ConfigManager>();
|
||||
|
||||
// Bind core services as instances
|
||||
builder.registerInstance(eventBus).as<IEventBus>();
|
||||
|
||||
// Register repositories
|
||||
builder.registerType(MockEventRepository).as<IEventRepository>();
|
||||
|
||||
// Register renderers
|
||||
builder.registerType(DateHeaderRenderer).as<IHeaderRenderer>().singleInstance();
|
||||
builder.registerType(DateColumnRenderer).as<ColumnRenderer>().singleInstance();
|
||||
builder.registerType(DateEventRenderer).as<IEventRenderer>().singleInstance();
|
||||
builder.registerType(DateHeaderRenderer).as<IHeaderRenderer>();
|
||||
builder.registerType(DateColumnRenderer).as<ColumnRenderer>();
|
||||
builder.registerType(DateEventRenderer).as<IEventRenderer>();
|
||||
|
||||
// Register core services and utilities
|
||||
builder.registerType(DateService).as<DateService>().singleInstance();
|
||||
builder.registerType(EventStackManager).as<EventStackManager>().singleInstance();
|
||||
builder.registerType(EventLayoutCoordinator).as<EventLayoutCoordinator>().singleInstance();
|
||||
builder.registerType(GridStyleManager).as<GridStyleManager>().singleInstance();
|
||||
builder.registerType(WorkHoursManager).as<WorkHoursManager>().singleInstance();
|
||||
builder.registerType(URLManager).as<URLManager>().singleInstance();
|
||||
builder.registerType(TimeFormatter).as<TimeFormatter>().singleInstance();
|
||||
builder.registerType(PositionUtils).as<PositionUtils>().singleInstance();
|
||||
builder.registerType(DateService).as<DateService>();
|
||||
builder.registerType(EventStackManager).as<EventStackManager>();
|
||||
builder.registerType(EventLayoutCoordinator).as<EventLayoutCoordinator>();
|
||||
builder.registerType(WorkHoursManager).as<WorkHoursManager>();
|
||||
builder.registerType(URLManager).as<URLManager>();
|
||||
builder.registerType(TimeFormatter).as<TimeFormatter>();
|
||||
builder.registerType(PositionUtils).as<PositionUtils>();
|
||||
// Note: AllDayLayoutEngine is instantiated per-operation with specific dates, not a singleton
|
||||
builder.registerType(NavigationRenderer).as<NavigationRenderer>().singleInstance();
|
||||
builder.registerType(AllDayEventRenderer).as<AllDayEventRenderer>().singleInstance();
|
||||
builder.registerType(NavigationRenderer).as<NavigationRenderer>();
|
||||
builder.registerType(AllDayEventRenderer).as<AllDayEventRenderer>();
|
||||
|
||||
builder.registerType(EventRenderingService).as<EventRenderingService>().singleInstance();
|
||||
builder.registerType(GridRenderer).as<GridRenderer>().singleInstance();
|
||||
builder.registerType(GridManager).as<GridManager>().singleInstance();
|
||||
builder.registerType(ScrollManager).as<ScrollManager>().singleInstance();
|
||||
builder.registerType(NavigationManager).as<NavigationManager>().singleInstance();
|
||||
builder.registerType(ViewManager).as<ViewManager>().singleInstance();
|
||||
builder.registerType(DragDropManager).as<DragDropManager>().singleInstance();
|
||||
builder.registerType(AllDayManager).as<AllDayManager>().singleInstance();
|
||||
builder.registerType(ResizeHandleManager).as<ResizeHandleManager>().singleInstance();
|
||||
builder.registerType(EdgeScrollManager).as<EdgeScrollManager>().singleInstance();
|
||||
builder.registerType(DragHoverManager).as<DragHoverManager>().singleInstance();
|
||||
builder.registerType(HeaderManager).as<HeaderManager>().singleInstance();
|
||||
builder.registerType(CalendarManager).as<CalendarManager>().singleInstance();
|
||||
builder.registerType(EventRenderingService).as<EventRenderingService>();
|
||||
builder.registerType(GridRenderer).as<GridRenderer>();
|
||||
builder.registerType(GridManager).as<GridManager>();
|
||||
builder.registerType(ScrollManager).as<ScrollManager>();
|
||||
builder.registerType(NavigationManager).as<NavigationManager>();
|
||||
builder.registerType(ViewManager).as<ViewManager>();
|
||||
builder.registerType(DragDropManager).as<DragDropManager>();
|
||||
builder.registerType(AllDayManager).as<AllDayManager>();
|
||||
builder.registerType(ResizeHandleManager).as<ResizeHandleManager>();
|
||||
builder.registerType(EdgeScrollManager).as<EdgeScrollManager>();
|
||||
builder.registerType(DragHoverManager).as<DragHoverManager>();
|
||||
builder.registerType(HeaderManager).as<HeaderManager>();
|
||||
builder.registerType(CalendarManager).as<CalendarManager>();
|
||||
|
||||
builder.registerType(EventManager).as<EventManager>().singleInstance();
|
||||
builder.registerType(EventManager).as<EventManager>();
|
||||
|
||||
// Build the container
|
||||
const app = builder.build();
|
||||
|
||||
// Get managers from container
|
||||
const eb = app.resolveType<IEventBus>();
|
||||
const configManager = app.resolveType<ConfigManager>();
|
||||
const calendarManager = app.resolveType<CalendarManager>();
|
||||
const eventManager = app.resolveType<EventManager>();
|
||||
const resizeHandleManager = app.resolveType<ResizeHandleManager>();
|
||||
|
|
@ -137,6 +143,9 @@ async function initializeCalendar(): Promise<void> {
|
|||
const allDayManager = app.resolveType<AllDayManager>();
|
||||
const urlManager = app.resolveType<URLManager>();
|
||||
|
||||
// Initialize CSS variables before any rendering
|
||||
configManager.initialize();
|
||||
|
||||
// Initialize managers
|
||||
await calendarManager.initialize?.();
|
||||
await resizeHandleManager.initialize?.();
|
||||
|
|
|
|||
|
|
@ -25,10 +25,19 @@ interface GridSettings {
|
|||
/**
|
||||
* ConfigManager - Handles configuration updates with event emission
|
||||
* Wraps static CalendarConfig with event-driven functionality for DI system
|
||||
* Also manages CSS custom properties that reflect config values
|
||||
*/
|
||||
export class ConfigManager {
|
||||
constructor(private eventBus: IEventBus) {}
|
||||
|
||||
/**
|
||||
* Initialize CSS variables on startup
|
||||
* Must be called after DOM is ready but before any rendering
|
||||
*/
|
||||
public initialize(): void {
|
||||
this.updateCSSVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a config value and emit event
|
||||
*/
|
||||
|
|
@ -36,6 +45,9 @@ export class ConfigManager {
|
|||
const oldValue = CalendarConfig.get(key);
|
||||
CalendarConfig.set(key, value);
|
||||
|
||||
// Update CSS variables to reflect config change
|
||||
this.updateCSSVariables();
|
||||
|
||||
// Emit config update event
|
||||
this.eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
||||
key,
|
||||
|
|
@ -59,6 +71,9 @@ export class ConfigManager {
|
|||
updateGridSettings(updates: Partial<GridSettings>): void {
|
||||
CalendarConfig.updateGridSettings(updates);
|
||||
|
||||
// Update CSS variables to reflect config change
|
||||
this.updateCSSVariables();
|
||||
|
||||
// Emit event after update
|
||||
this.eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
||||
key: 'gridSettings',
|
||||
|
|
@ -89,6 +104,9 @@ export class ConfigManager {
|
|||
const oldWorkWeek = CalendarConfig.getCurrentWorkWeek();
|
||||
CalendarConfig.setWorkWeek(workWeekId);
|
||||
|
||||
// Update CSS variables to reflect config change
|
||||
this.updateCSSVariables();
|
||||
|
||||
// Emit event if changed
|
||||
if (oldWorkWeek !== workWeekId) {
|
||||
this.eventBus.emit(CoreEvents.REFRESH_REQUESTED, {
|
||||
|
|
@ -98,4 +116,59 @@ export class ConfigManager {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all CSS custom properties based on current config
|
||||
* This keeps the DOM in sync with config values
|
||||
*/
|
||||
private updateCSSVariables(): void {
|
||||
const root = document.documentElement;
|
||||
const gridSettings = CalendarConfig.getGridSettings();
|
||||
const calendar = document.querySelector('swp-calendar') as HTMLElement;
|
||||
|
||||
// Set time-related CSS variables
|
||||
root.style.setProperty('--header-height', '80px'); // Fixed header height
|
||||
root.style.setProperty('--hour-height', `${gridSettings.hourHeight}px`);
|
||||
root.style.setProperty('--minute-height', `${gridSettings.hourHeight / 60}px`);
|
||||
root.style.setProperty('--snap-interval', gridSettings.snapInterval.toString());
|
||||
root.style.setProperty('--day-start-hour', gridSettings.dayStartHour.toString());
|
||||
root.style.setProperty('--day-end-hour', gridSettings.dayEndHour.toString());
|
||||
root.style.setProperty('--work-start-hour', gridSettings.workStartHour.toString());
|
||||
root.style.setProperty('--work-end-hour', gridSettings.workEndHour.toString());
|
||||
|
||||
// Set column count based on view
|
||||
const columnCount = this.calculateColumnCount();
|
||||
root.style.setProperty('--grid-columns', columnCount.toString());
|
||||
|
||||
// Set column width based on fitToWidth setting
|
||||
if (gridSettings.fitToWidth) {
|
||||
root.style.setProperty('--day-column-min-width', '50px'); // Small min-width allows columns to fit available space
|
||||
} else {
|
||||
root.style.setProperty('--day-column-min-width', '250px'); // Default min-width for horizontal scroll mode
|
||||
}
|
||||
|
||||
// Set fitToWidth data attribute for CSS targeting
|
||||
if (calendar) {
|
||||
calendar.setAttribute('data-fit-to-width', gridSettings.fitToWidth.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate number of columns based on view
|
||||
*/
|
||||
private calculateColumnCount(): number {
|
||||
const dateSettings = CalendarConfig.getDateViewSettings();
|
||||
const workWeekSettings = CalendarConfig.getWorkWeekSettings();
|
||||
|
||||
switch (dateSettings.period) {
|
||||
case 'day':
|
||||
return 1;
|
||||
case 'week':
|
||||
return workWeekSettings.totalDays;
|
||||
case 'month':
|
||||
return workWeekSettings.totalDays; // Use work week for month view too
|
||||
default:
|
||||
return workWeekSettings.totalDays;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,83 +2,43 @@ import { IEventBus, CalendarEvent } from '../types/CalendarTypes';
|
|||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
import { DateService } from '../utils/DateService';
|
||||
|
||||
interface RawEventData {
|
||||
id: string;
|
||||
title: string;
|
||||
start: string | Date;
|
||||
end: string | Date;
|
||||
type : string;
|
||||
color?: string;
|
||||
allDay?: boolean;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
import { IEventRepository } from '../repositories/IEventRepository';
|
||||
|
||||
/**
|
||||
* EventManager - Event lifecycle and CRUD operations
|
||||
* Handles data loading and event management
|
||||
* Handles event management and CRUD operations
|
||||
*/
|
||||
export class EventManager {
|
||||
|
||||
private events: CalendarEvent[] = [];
|
||||
private rawData: RawEventData[] | null = null;
|
||||
private dateService: DateService;
|
||||
private config: CalendarConfig;
|
||||
private repository: IEventRepository;
|
||||
|
||||
constructor(
|
||||
private eventBus: IEventBus,
|
||||
dateService: DateService,
|
||||
config: CalendarConfig
|
||||
config: CalendarConfig,
|
||||
repository: IEventRepository
|
||||
) {
|
||||
this.dateService = dateService;
|
||||
this.config = config;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load event data from JSON file
|
||||
* Load event data from repository
|
||||
*/
|
||||
public async loadData(): Promise<void> {
|
||||
try {
|
||||
await this.loadMockData();
|
||||
this.events = await this.repository.loadEvents();
|
||||
} catch (error) {
|
||||
console.error('Failed to load event data:', error);
|
||||
this.events = [];
|
||||
this.rawData = null;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimized mock data loading
|
||||
*/
|
||||
private async loadMockData(): Promise<void> {
|
||||
const jsonFile = 'data/mock-events.json';
|
||||
|
||||
const response = await fetch(jsonFile);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock events: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Store raw data and process in one operation
|
||||
this.rawData = data;
|
||||
this.events = this.processCalendarData(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process raw event data and convert to CalendarEvent objects
|
||||
*/
|
||||
private processCalendarData(data: RawEventData[]): CalendarEvent[] {
|
||||
return data.map((event): CalendarEvent => ({
|
||||
...event,
|
||||
start: new Date(event.start),
|
||||
end: new Date(event.end),
|
||||
type : event.type,
|
||||
allDay: event.allDay || false,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get events with optional copying for performance
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { eventBus } from '../core/EventBus';
|
|||
import { CoreEvents } from '../constants/CoreEvents';
|
||||
import { CalendarView } from '../types/CalendarTypes';
|
||||
import { GridRenderer } from '../renderers/GridRenderer';
|
||||
import { GridStyleManager } from '../renderers/GridStyleManager';
|
||||
import { DateService } from '../utils/DateService';
|
||||
|
||||
/**
|
||||
|
|
@ -18,16 +17,13 @@ export class GridManager {
|
|||
private currentDate: Date = new Date();
|
||||
private currentView: CalendarView = 'week';
|
||||
private gridRenderer: GridRenderer;
|
||||
private styleManager: GridStyleManager;
|
||||
private dateService: DateService;
|
||||
|
||||
constructor(
|
||||
gridRenderer: GridRenderer,
|
||||
styleManager: GridStyleManager,
|
||||
dateService: DateService
|
||||
) {
|
||||
this.gridRenderer = gridRenderer;
|
||||
this.styleManager = styleManager;
|
||||
this.dateService = dateService;
|
||||
this.init();
|
||||
}
|
||||
|
|
@ -85,15 +81,13 @@ export class GridManager {
|
|||
|
||||
/**
|
||||
* Main render method - delegates to GridRenderer
|
||||
* Note: CSS variables are automatically updated by ConfigManager when config changes
|
||||
*/
|
||||
public async render(): Promise<void> {
|
||||
if (!this.container) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update CSS variables first
|
||||
this.styleManager.updateGridStyles();
|
||||
|
||||
// Delegate to GridRenderer with current view context
|
||||
this.gridRenderer.renderGrid(
|
||||
this.container,
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
import { CalendarConfig } from '../core/CalendarConfig';
|
||||
|
||||
interface GridSettings {
|
||||
hourHeight: number;
|
||||
snapInterval: number;
|
||||
dayStartHour: number;
|
||||
dayEndHour: number;
|
||||
workStartHour: number;
|
||||
workEndHour: number;
|
||||
fitToWidth?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* GridStyleManager - Manages CSS variables and styling for the grid
|
||||
* Separated from GridManager to follow Single Responsibility Principle
|
||||
*/
|
||||
export class GridStyleManager {
|
||||
private config: CalendarConfig;
|
||||
|
||||
constructor(config: CalendarConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all grid CSS variables
|
||||
*/
|
||||
public updateGridStyles(): void {
|
||||
const root = document.documentElement;
|
||||
const gridSettings = this.config.getGridSettings();
|
||||
const calendar = document.querySelector('swp-calendar') as HTMLElement;
|
||||
|
||||
// Set CSS variables for time and grid measurements
|
||||
this.setTimeVariables(root, gridSettings);
|
||||
|
||||
// Set column count based on view
|
||||
const columnCount = this.calculateColumnCount();
|
||||
root.style.setProperty('--grid-columns', columnCount.toString());
|
||||
|
||||
// Set column width based on fitToWidth setting
|
||||
this.setColumnWidth(root, gridSettings);
|
||||
|
||||
// Set fitToWidth data attribute for CSS targeting
|
||||
if (calendar) {
|
||||
calendar.setAttribute('data-fit-to-width', gridSettings.fitToWidth.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time-related CSS variables
|
||||
*/
|
||||
private setTimeVariables(root: HTMLElement, gridSettings: GridSettings): void {
|
||||
root.style.setProperty('--header-height', '80px'); // Fixed header height
|
||||
root.style.setProperty('--hour-height', `${gridSettings.hourHeight}px`);
|
||||
root.style.setProperty('--minute-height', `${gridSettings.hourHeight / 60}px`);
|
||||
root.style.setProperty('--snap-interval', gridSettings.snapInterval.toString());
|
||||
root.style.setProperty('--day-start-hour', gridSettings.dayStartHour.toString());
|
||||
root.style.setProperty('--day-end-hour', gridSettings.dayEndHour.toString());
|
||||
root.style.setProperty('--work-start-hour', gridSettings.workStartHour.toString());
|
||||
root.style.setProperty('--work-end-hour', gridSettings.workEndHour.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate number of columns based on view
|
||||
*/
|
||||
private calculateColumnCount(): number {
|
||||
const dateSettings = this.config.getDateViewSettings();
|
||||
const workWeekSettings = this.config.getWorkWeekSettings();
|
||||
|
||||
switch (dateSettings.period) {
|
||||
case 'day':
|
||||
return 1;
|
||||
case 'week':
|
||||
return workWeekSettings.totalDays;
|
||||
case 'month':
|
||||
return workWeekSettings.totalDays; // Use work week for month view too
|
||||
default:
|
||||
return workWeekSettings.totalDays;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set column width based on fitToWidth setting
|
||||
*/
|
||||
private setColumnWidth(root: HTMLElement, gridSettings: GridSettings): void {
|
||||
if (gridSettings.fitToWidth) {
|
||||
root.style.setProperty('--day-column-min-width', '50px'); // Small min-width allows columns to fit available space
|
||||
} else {
|
||||
root.style.setProperty('--day-column-min-width', '250px'); // Default min-width for horizontal scroll mode
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
20
src/repositories/IEventRepository.ts
Normal file
20
src/repositories/IEventRepository.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { CalendarEvent } from '../types/CalendarTypes';
|
||||
|
||||
/**
|
||||
* IEventRepository - Interface for event data loading
|
||||
*
|
||||
* Abstracts the data source for calendar events, allowing easy switching
|
||||
* between mock data, REST API, GraphQL, or other data sources.
|
||||
*
|
||||
* Implementations:
|
||||
* - MockEventRepository: Loads from local JSON file
|
||||
* - ApiEventRepository: (Future) Loads from backend API
|
||||
*/
|
||||
export interface IEventRepository {
|
||||
/**
|
||||
* Load all calendar events from the data source
|
||||
* @returns Promise resolving to array of CalendarEvent objects
|
||||
* @throws Error if loading fails
|
||||
*/
|
||||
loadEvents(): Promise<CalendarEvent[]>;
|
||||
}
|
||||
53
src/repositories/MockEventRepository.ts
Normal file
53
src/repositories/MockEventRepository.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { CalendarEvent } from '../types/CalendarTypes';
|
||||
import { IEventRepository } from './IEventRepository';
|
||||
|
||||
interface RawEventData {
|
||||
id: string;
|
||||
title: string;
|
||||
start: string | Date;
|
||||
end: string | Date;
|
||||
type: string;
|
||||
color?: string;
|
||||
allDay?: boolean;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockEventRepository - Loads event data from local JSON file
|
||||
*
|
||||
* This repository implementation fetches mock event data from a static JSON file.
|
||||
* Used for development and testing before backend API is available.
|
||||
*
|
||||
* Data Source: data/mock-events.json
|
||||
*/
|
||||
export class MockEventRepository implements IEventRepository {
|
||||
private readonly dataUrl = 'data/mock-events.json';
|
||||
|
||||
public async loadEvents(): Promise<CalendarEvent[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock events: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawEventData[] = await response.json();
|
||||
|
||||
return this.processCalendarData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load event data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private processCalendarData(data: RawEventData[]): CalendarEvent[] {
|
||||
return data.map((event): CalendarEvent => ({
|
||||
...event,
|
||||
start: new Date(event.start),
|
||||
end: new Date(event.end),
|
||||
type: event.type,
|
||||
allDay: event.allDay || false,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/**
|
||||
* ViewStrategy - Strategy pattern for different calendar view types
|
||||
* Allows clean separation between week view, month view, day view etc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context object passed to strategy methods
|
||||
*/
|
||||
export interface ViewContext {
|
||||
currentDate: Date;
|
||||
container: HTMLElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout configuration specific to each view type
|
||||
*/
|
||||
export interface ViewLayoutConfig {
|
||||
needsTimeAxis: boolean;
|
||||
columnCount: number;
|
||||
scrollable: boolean;
|
||||
eventPositioning: 'time-based' | 'cell-based';
|
||||
}
|
||||
|
||||
/**
|
||||
* Base strategy interface for all view types
|
||||
*/
|
||||
export interface ViewStrategy {
|
||||
/**
|
||||
* Get the layout configuration for this view
|
||||
*/
|
||||
getLayoutConfig(): ViewLayoutConfig;
|
||||
|
||||
/**
|
||||
* Render the grid structure for this view
|
||||
*/
|
||||
renderGrid(context: ViewContext): void;
|
||||
|
||||
/**
|
||||
* Calculate next period for navigation
|
||||
*/
|
||||
getNextPeriod(currentDate: Date): Date;
|
||||
|
||||
/**
|
||||
* Calculate previous period for navigation
|
||||
*/
|
||||
getPreviousPeriod(currentDate: Date): Date;
|
||||
|
||||
/**
|
||||
* Get display label for current period
|
||||
*/
|
||||
getPeriodLabel(date: Date): string;
|
||||
|
||||
/**
|
||||
* Get the dates that should be displayed in this view
|
||||
*/
|
||||
getDisplayDates(baseDate: Date): Date[];
|
||||
|
||||
/**
|
||||
* Get the period start and end dates for event filtering
|
||||
*/
|
||||
getPeriodRange(baseDate: Date): { startDate: Date; endDate: Date };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue