diff --git a/src/managers/ColumnDetector.ts b/src/managers/ColumnDetector.ts index ce9be43..48c4101 100644 --- a/src/managers/ColumnDetector.ts +++ b/src/managers/ColumnDetector.ts @@ -19,6 +19,7 @@ export class ColumnDetector { private autoScrollAnimationId: number | null = null; private scrollSpeed = 10; // pixels per frame private scrollThreshold = 30; // pixels from edge + private currentMouseY = 0; // Track current mouse Y for scroll updates // Konfiguration for snap interval private snapIntervalMinutes = 15; // 15 minutter @@ -81,14 +82,23 @@ export class ColumnDetector { eventBus.on('header:mouseover', (event) => { const { dayHeader, headerRenderer } = (event as CustomEvent).detail; if (this.isMouseDown && this.draggedClone) { - console.log('Dragging clone over header - calling addToAllDay'); + console.log('Dragging clone over header - expanding and converting to all-day'); headerRenderer.addToAllDay(dayHeader); + + // Convert clone to all-day format immediately + const targetDate = dayHeader.dataset.date; + if (targetDate) { + this.convertToAllDayPreview(targetDate); + } } }); } private handleMouseMove(event: MouseEvent): void { + // Track current mouse position for auto-scroll updates + this.currentMouseY = event.clientY; + // Hvis musen er holdt nede, tjek for snap interval vertikal bevægelse if (this.isMouseDown) { const deltaY = Math.abs(event.clientY - this.lastLoggedPosition.y); @@ -102,17 +112,26 @@ export class ColumnDetector { }); this.lastLoggedPosition = { x: event.clientX, y: event.clientY }; - // Opdater klonens Y-position ved snap interval (relativt til kolonne) + // Snap klonens position til nærmeste 15-min interval if (this.draggedClone && this.draggedClone.parentElement) { const columnRect = this.draggedClone.parentElement.getBoundingClientRect(); - const relativeY = event.clientY - columnRect.top - this.mouseOffset.y; - this.draggedClone.style.top = relativeY + 'px'; + const rawRelativeY = event.clientY - columnRect.top - this.mouseOffset.y; + + // Snap til nærmeste 15-min grid + const snappedY = Math.round(rawRelativeY / this.snapDistancePx) * this.snapDistancePx; + this.draggedClone.style.top = snappedY + 'px'; } } + // Kontinuerlig opdatering under auto-scroll for at sikre klonen følger musen + if (this.draggedClone && this.draggedClone.parentElement && this.autoScrollAnimationId !== null) { + const columnRect = this.draggedClone.parentElement.getBoundingClientRect(); + const relativeY = event.clientY - columnRect.top - this.mouseOffset.y; + this.draggedClone.style.top = relativeY + 'px'; + } + // Auto-scroll detection når der er en aktiv clone if (this.draggedClone) { - console.log('ColumnDetector: Checking auto-scroll, mouse at:', event.clientY); this.checkAutoScroll(event); } } @@ -287,18 +306,24 @@ export class ColumnDetector { // Drop operationen: fade out original og remove clone suffix if (this.originalEvent && this.draggedClone) { - // Fade out og fjern originalen - this.fadeOutAndRemove(this.originalEvent); + // Check if clone was converted to all-day (is now in header) + const cloneInHeader = this.draggedClone.closest('swp-calendar-header'); - // Fjern clone suffix fra klonen - this.removeClonePrefix(this.draggedClone); + if (cloneInHeader) { + console.log('Drop completed: all-day event created'); + // Clone is now an all-day event, just fade out original + this.fadeOutAndRemove(this.originalEvent); + } else { + console.log('Drop in regular area - keeping as timed event'); + // Normal drop: fade out original and keep clone as timed + this.fadeOutAndRemove(this.originalEvent); + this.removeClonePrefix(this.draggedClone); + } // Ryd op this.originalEvent = null; this.draggedClone = null; this.scrollContainer = null; - - console.log('Drop completed: original faded out and removed, clone became permanent'); } // Cleanup hvis ingen drop (ingen clone var aktiv) @@ -343,14 +368,6 @@ export class ColumnDetector { const distanceFromTop = mouseY - containerRect.top; const distanceFromBottom = containerRect.bottom - mouseY; - console.log('ColumnDetector: Auto-scroll check:', { - mouseY, - containerTop: containerRect.top, - containerBottom: containerRect.bottom, - distanceFromTop: Math.round(distanceFromTop), - distanceFromBottom: Math.round(distanceFromBottom), - threshold: this.scrollThreshold - }); // Check if we need to scroll up if (distanceFromTop <= this.scrollThreshold && distanceFromTop > 0) { @@ -386,6 +403,13 @@ export class ColumnDetector { const scrollAmount = direction === 'up' ? -this.scrollSpeed : this.scrollSpeed; this.scrollContainer.scrollTop += scrollAmount; + // Update clone position based on current mouse position after scroll + if (this.draggedClone && this.draggedClone.parentElement) { + const columnRect = this.draggedClone.parentElement.getBoundingClientRect(); + const relativeY = this.currentMouseY - columnRect.top - this.mouseOffset.y; + this.draggedClone.style.top = relativeY + 'px'; + } + // Continue animation this.autoScrollAnimationId = requestAnimationFrame(scroll); }; @@ -403,6 +427,114 @@ export class ColumnDetector { } } + /** + * Convert dragged clone to all-day event preview + */ + private convertToAllDayPreview(targetDate: string): void { + if (!this.draggedClone) return; + + // Only convert once + if (this.draggedClone.tagName === 'SWP-ALLDAY-EVENT') { + return; + } + + // Transform clone to all-day format + this.transformCloneToAllDay(this.draggedClone, targetDate); + + // No need to recalculate height - addToAllDay already handles this + console.log(`Converted clone to all-day preview for date: ${targetDate}`); + } + + /** + * Transform clone from timed event to all-day event format + */ + private transformCloneToAllDay(clone: HTMLElement, targetDate: string): void { + console.log('transformCloneToAllDay called with:', { clone, targetDate }); + + const calendarHeader = document.querySelector('swp-calendar-header'); + if (!calendarHeader) { + console.error('No calendar header found'); + return; + } + + // Find or create all-day container for target date + const container = this.findOrCreateAllDayContainer(calendarHeader as HTMLElement, targetDate); + if (!container) { + console.error('No container found/created'); + return; + } + + // Extract title from original clone (remove time info) + const titleElement = clone.querySelector('swp-event-title'); + const eventTitle = titleElement ? titleElement.textContent || 'Untitled Event' : 'Untitled Event'; + + console.log('Creating all-day event with title:', eventTitle); + + // Create new all-day event element + const allDayEvent = document.createElement('swp-allday-event'); + allDayEvent.setAttribute('data-event-id', clone.dataset.eventId || ''); + allDayEvent.setAttribute('data-type', clone.dataset.type || 'work'); + allDayEvent.textContent = eventTitle; + + console.log('All-day event created:', allDayEvent); + + // Remove the original clone from its current parent + if (clone.parentElement) { + console.log('Removing original clone from parent:', clone.parentElement); + clone.parentElement.removeChild(clone); + } + + // Add new all-day event to container + container.appendChild(allDayEvent); + console.log('All-day event added to container:', container); + + // Update reference to point to new element + this.draggedClone = allDayEvent; + + console.log(`Transformed clone to all-day event in container for date: ${targetDate}`); + } + + /** + * Find existing or create new all-day container for specific date + */ + private findOrCreateAllDayContainer(calendarHeader: HTMLElement, targetDate: string): HTMLElement | null { + // Find day headers to determine column index + const dayHeaders = calendarHeader.querySelectorAll('swp-day-header'); + let columnIndex = -1; + + for (let i = 0; i < dayHeaders.length; i++) { + const dayHeader = dayHeaders[i] as HTMLElement; + if (dayHeader.dataset.date === targetDate) { + columnIndex = i + 1; // 1-based grid index + break; + } + } + + if (columnIndex === -1) { + console.error(`Could not find column for date: ${targetDate}`); + return null; + } + + // Look for existing container for this single column + const containerKey = `${columnIndex}-1`; // single column span + let container = calendarHeader.querySelector(`swp-allday-container[data-container-key="${containerKey}"]`); + + if (!container) { + // Create new container + container = document.createElement('swp-allday-container'); + container.setAttribute('data-container-key', containerKey); + container.setAttribute('data-date', targetDate); + (container as HTMLElement).style.gridColumn = `${columnIndex}`; + (container as HTMLElement).style.gridRow = '2'; // All-day row + calendarHeader.appendChild(container); + + console.log(`Created new all-day container for column ${columnIndex}, date: ${targetDate}`); + } + + return container as HTMLElement; + } + + public destroy(): void { this.stopAutoScroll(); document.body.removeEventListener('mousemove', this.handleMouseMove.bind(this));