Improves event layout and stacking logic

Refactors the event layout and stacking logic based on review feedback.

This includes:
- Merging conflicting event groups to prevent inconsistencies.
- Implementing minimal stack level assignment using a min-heap.
- Consolidating styling and using DateService for drag operations.
- Adding reflow after drag and drop.
- Improving the column event filtering to include events overlapping midnight.
- Ensuring explicit sorting of events for grid layout.
This commit is contained in:
Janus C. H. Knudsen 2025-10-06 21:16:29 +02:00
parent b590467f60
commit faa59f6a3c
19 changed files with 1502 additions and 55 deletions

View file

@ -85,7 +85,7 @@ export class DateEventRenderer implements EventRendererStrategy {
// Delegate to SwpEventElement to update position and timestamps
const swpEvent = this.draggedClone as SwpEventElement;
const columnDate = new Date(payload.columnBounds.date);
const columnDate = this.dateService.parseISO(payload.columnBounds.date);
swpEvent.updatePosition(columnDate, payload.snappedY);
}
@ -111,11 +111,11 @@ export class DateEventRenderer implements EventRendererStrategy {
const eventsLayer = dragColumnChangeEvent.newColumn.element.querySelector('swp-events-layer');
if (eventsLayer && this.draggedClone.parentElement !== eventsLayer) {
eventsLayer.appendChild(this.draggedClone);
// Recalculate timestamps with new column date
const currentTop = parseFloat(this.draggedClone.style.top) || 0;
const swpEvent = this.draggedClone as SwpEventElement;
const columnDate = new Date(dragColumnChangeEvent.newColumn.date);
const columnDate = this.dateService.parseISO(dragColumnChangeEvent.newColumn.date);
swpEvent.updatePosition(columnDate, currentTop);
}
}
@ -221,16 +221,15 @@ export class DateEventRenderer implements EventRendererStrategy {
// Position from layout
groupElement.style.top = `${gridGroup.position.top}px`;
// Add inline styles for margin-left and z-index (guaranteed to work)
groupElement.style.marginLeft = `${gridGroup.stackLevel * 15}px`;
groupElement.style.zIndex = `${this.stackManager.calculateZIndex(gridGroup.stackLevel)}`;
// Add stack-link attribute for drag-drop (group acts as a stacked item)
const stackLink = {
stackLevel: gridGroup.stackLevel
};
this.stackManager.applyStackLinkToElement(groupElement, stackLink);
// Apply visual styling (margin-left and z-index) using StackManager
this.stackManager.applyVisualStyling(groupElement, gridGroup.stackLevel);
// Render each column
const earliestEvent = gridGroup.events[0];
gridGroup.columns.forEach(columnEvents => {
@ -330,11 +329,14 @@ export class DateEventRenderer implements EventRendererStrategy {
return [];
}
const columnEvents = events.filter(event => {
const eventDateStr = this.dateService.formatISODate(event.start);
const matches = eventDateStr === columnDate;
// Create start and end of day for interval overlap check
const columnStart = this.dateService.parseISO(`${columnDate}T00:00:00`);
const columnEnd = this.dateService.parseISO(`${columnDate}T23:59:59.999`);
return matches;
const columnEvents = events.filter(event => {
// Interval overlap: event overlaps with column day if event.start < columnEnd AND event.end > columnStart
const overlaps = event.start < columnEnd && event.end > columnStart;
return overlaps;
});
return columnEvents;