From ae42de1f3b35af19f9370394cf9df8aec1b66797 Mon Sep 17 00:00:00 2001 From: Janus Knudsen Date: Sun, 31 Aug 2025 23:48:34 +0200 Subject: [PATCH] Improves all-day event rendering and placement Simplifies and improves the all-day event rendering process, ensuring consistent container creation and proper placement of events. - Ensures all-day containers are consistently created during header rendering, preventing potential issues with event placement. - Removes the complex and unreliable mouseover detection for all-day conversion, simplifying the event dragging logic. - Eliminates the dynamic all-day row height calculation, relying on CSS for layout control. - Prevents errors when the all-day container is missing. --- src/renderers/EventRenderer.ts | 103 ++-------------------------- src/renderers/HeaderRenderer.ts | 9 ++- wwwroot/css/calendar-base-css.css | 2 +- wwwroot/css/calendar-layout-css.css | 6 +- 4 files changed, 15 insertions(+), 105 deletions(-) diff --git a/src/renderers/EventRenderer.ts b/src/renderers/EventRenderer.ts index 526dba6..359f617 100644 --- a/src/renderers/EventRenderer.ts +++ b/src/renderers/EventRenderer.ts @@ -63,83 +63,8 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { const { eventId, targetDate, headerRenderer } = (event as CustomEvent).detail; this.handleConvertToAllDay(eventId, targetDate, headerRenderer); }); - - // Listen for header mouseover events (like original ColumnDetector) - eventBus.on('header:mouseover', (event) => { - const { element, targetDate, headerRenderer } = (event as CustomEvent).detail; - - if (this.draggedClone && targetDate) { - // Scenario 1: Timed event being dragged to header - convert to all-day - if (this.draggedClone.tagName === 'SWP-EVENT') { - headerRenderer.addToAllDay(element); - this.convertToAllDayPreview(targetDate); - } - - // Scenario 2: All-day event being moved to different day - else if (this.draggedClone.tagName === 'SWP-ALLDAY-EVENT') { - const currentDate = this.draggedClone.parentElement?.getAttribute('data-date'); - if (currentDate !== targetDate) { - this.moveAllDayToNewDate(targetDate); - } - } - } - }); - - // Setup header mouseover detection for all-day conversion - this.setupHeaderMouseoverDetection(); } - - /** - * Setup header mouseover detection during drag - */ - private setupHeaderMouseoverDetection(): void { - document.addEventListener('mouseover', (event) => { - if (!this.draggedClone) return; // Only during active drag - - const target = event.target as HTMLElement; - - // Check if mouse is over a day header - let dayHeader = target.closest('swp-day-header') as HTMLElement; - if (dayHeader) { - const targetDate = dayHeader.dataset.date; - if (targetDate && this.draggedClone.tagName === 'SWP-EVENT') { - - // Find the header renderer from the calendar header - const calendarHeader = dayHeader.closest('swp-calendar-header'); - if (calendarHeader) { - // Emit header mouseover event like the original ColumnDetector did - eventBus.emit('header:mouseover', { - element: dayHeader, - targetDate: targetDate, - headerRenderer: this.getHeaderRenderer() - }); - } - } - } - }); - } - - /** - * Get the header renderer instance for triggering addToAllDay - */ - private getHeaderRenderer(): any { - // For now, we'll create a simple object with the addToAllDay method - // This mimics what ColumnDetector had access to - return { - addToAllDay: (element: HTMLElement) => { - // Find the calendar header and call the HeaderRenderer's addToAllDay method - const calendarHeader = element.closest('swp-calendar-header') as HTMLElement; - if (calendarHeader) { - // Import and use HeaderRenderer directly - import('./HeaderRenderer').then(({ BaseHeaderRenderer }) => { - const headerRenderer = new BaseHeaderRenderer(); - headerRenderer.addToAllDay(element); - }); - } - } - }; - } - + /** * Get original event duration from data-duration attribute */ @@ -496,9 +421,10 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { return; } - // Find the all-day container + // Find the all-day container (should always exist now) const allDayContainer = calendarHeader.querySelector('swp-allday-container') as HTMLElement; if (!allDayContainer) { + console.warn('All-day container not found - this should not happen'); return; } @@ -506,8 +432,7 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { allDayContainer.innerHTML = ''; if (allDayEvents.length === 0) { - // No events - just return - this.updateAllDayHeight(1); + // No events - container exists but is empty and hidden return; } @@ -579,9 +504,6 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { allDayContainer.appendChild(allDayEvent); }); - - // Update height based on max row - this.updateAllDayHeight(maxRow); } @@ -651,23 +573,6 @@ export abstract class BaseEventRenderer implements EventRendererStrategy { return `${displayHour}:${minutes.toString().padStart(2, '0')} ${period}`; } - /** - * Update all-day row height and grid template based on number of rows - */ - private updateAllDayHeight(maxRows: number): void { - const root = document.documentElement; - const eventHeight = parseInt(getComputedStyle(root).getPropertyValue('--all-day-event-height')); - const calculatedHeight = maxRows * eventHeight; - root.style.setProperty('--all-day-row-height', `${calculatedHeight}px`); - - // Update grid-template-rows for all swp-allday-containers - const allDayContainers = document.querySelectorAll('swp-allday-container'); - allDayContainers.forEach(container => { - const gridRows = `repeat(${maxRows}, var(--all-day-event-height))`; - (container as HTMLElement).style.gridTemplateRows = gridRows; - }); - - } /** * Calculate grid column span for event diff --git a/src/renderers/HeaderRenderer.ts b/src/renderers/HeaderRenderer.ts index d27c7ec..89463b1 100644 --- a/src/renderers/HeaderRenderer.ts +++ b/src/renderers/HeaderRenderer.ts @@ -39,10 +39,10 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer { } /** - * Ensure all-day containers exist - but don't create them initially, use lazy creation + * Ensure all-day containers exist - always create them during header rendering */ ensureAllDayContainers(calendarHeader: HTMLElement): void { - // Do nothing initially - containers will be created when first needed + this.createAllDayMainStructure(calendarHeader); } private animateHeaderExpansion(calendarHeader: HTMLElement): void { @@ -163,6 +163,9 @@ export class DateHeaderRenderer extends BaseHeaderRenderer { calendarHeader.appendChild(header); }); + + // Always create all-day container after rendering headers + this.ensureAllDayContainers(calendarHeader); } } @@ -192,5 +195,7 @@ export class ResourceHeaderRenderer extends BaseHeaderRenderer { calendarHeader.appendChild(header); }); + // Always create all-day container after rendering headers + this.ensureAllDayContainers(calendarHeader); } } \ No newline at end of file diff --git a/wwwroot/css/calendar-base-css.css b/wwwroot/css/calendar-base-css.css index 28b605c..8f94c72 100644 --- a/wwwroot/css/calendar-base-css.css +++ b/wwwroot/css/calendar-base-css.css @@ -17,7 +17,7 @@ --week-days: 7; --header-height: 80px; --all-day-row-height: 0px; /* Default height for all-day events row */ - --allday-event-height: 26px; /* Height of single all-day event including gaps */ + --all-day-event-height: 26px; /* Height of single all-day event including gaps */ --stack-levels: 1; /* Number of stack levels for all-day events */ /* Time boundaries - Default fallback values */ diff --git a/wwwroot/css/calendar-layout-css.css b/wwwroot/css/calendar-layout-css.css index 2228408..477752b 100644 --- a/wwwroot/css/calendar-layout-css.css +++ b/wwwroot/css/calendar-layout-css.css @@ -143,7 +143,7 @@ swp-time-grid::after { swp-calendar-header { display: grid; grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr)); - grid-template-rows: var(--header-height) var(--all-day-row-height); /* Row 1: header height, Row 2: all-day events height */ + grid-template-rows: var(--header-height) auto; /* Row 1: header height, Row 2: auto for all-day events */ min-width: calc(var(--grid-columns, 7) * var(--day-column-min-width)); /* Dynamic width */ background: var(--color-surface); border-bottom: 1px solid var(--color-border); @@ -273,14 +273,14 @@ swp-allday-container { grid-row: 2; /* Second row of calendar header */ display: grid; grid-template-columns: repeat(var(--grid-columns, 7), minmax(var(--day-column-min-width), 1fr)); - grid-template-rows: repeat(1, var(--allday-event-height, 26px)); /* Default to 1 row, dynamically updated by JS */ + grid-template-rows: repeat(1, var(--all-day-event-height)); /* Default to 1 row, dynamically updated by JS */ gap: 2px; padding: 2px; align-items: center; overflow: hidden; /* Initially hidden - no CSS transitions, use Web Animations API */ - height: 0; + height: var(--all-day-row-height); min-height: 0; opacity: 0; }