From afe5b6b8997c96376576f95f812270771589f2b7 Mon Sep 17 00:00:00 2001 From: Janus Knudsen Date: Wed, 13 Aug 2025 23:37:23 +0200 Subject: [PATCH] Improves calendar navigation animation Replaces the setTimeout-based animation with the Web Animations API for smoother transitions. This change also introduces an event to notify other managers when the navigation animation is complete, allowing them to synchronize their states. --- src/constants/EventTypes.ts | 1 + src/managers/NavigationManager.ts | 87 ++++++++++++++++++------------- src/managers/ScrollManager.ts | 8 ++- 3 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/constants/EventTypes.ts b/src/constants/EventTypes.ts index 654a8f7..57db036 100644 --- a/src/constants/EventTypes.ts +++ b/src/constants/EventTypes.ts @@ -25,6 +25,7 @@ export const EventTypes = { WEEK_CHANGED: 'calendar:weekchanged', WEEK_INFO_UPDATED: 'calendar:weekinfoupdated', WEEK_CONTENT_RENDERED: 'calendar:weekcontentrendered', + NAVIGATION_ANIMATION_COMPLETE: 'calendar:navigationanimationcomplete', NAV_PREV: 'calendar:navprev', NAV_NEXT: 'calendar:navnext', NAV_TODAY: 'calendar:navtoday', diff --git a/src/managers/NavigationManager.ts b/src/managers/NavigationManager.ts index ea1ff73..2bdfb5f 100644 --- a/src/managers/NavigationManager.ts +++ b/src/managers/NavigationManager.ts @@ -152,46 +152,59 @@ export class NavigationManager { // Render new content for target week this.renderWeekContent(newGrid, targetWeek); - // Animate transition (POC animation) - requestAnimationFrame(() => { - // Slide out current grid - (currentGrid as HTMLElement).style.transform = direction === 'next' ? 'translateX(-100%)' : 'translateX(100%)'; - (currentGrid as HTMLElement).style.opacity = '0.5'; + // Animate transition using Web Animations API + const slideOutAnimation = (currentGrid as HTMLElement).animate([ + { transform: 'translateX(0)', opacity: '1' }, + { transform: direction === 'next' ? 'translateX(-100%)' : 'translateX(100%)', opacity: '0.5' } + ], { + duration: 400, + easing: 'ease-in-out', + fill: 'forwards' + }); + + const slideInAnimation = newGrid.animate([ + { transform: direction === 'next' ? 'translateX(100%)' : 'translateX(-100%)' }, + { transform: 'translateX(0)' } + ], { + duration: 400, + easing: 'ease-in-out', + fill: 'forwards' + }); + + // Handle animation completion + slideInAnimation.addEventListener('finish', () => { + // Cleanup: Remove all old grids except the new one + const allGrids = container.querySelectorAll('swp-grid-container'); + for (let i = 0; i < allGrids.length - 1; i++) { + allGrids[i].remove(); + } + + // Reset positioning + newGrid.style.position = 'relative'; - // Cleanup: Remove all old grids except the new one after animation - setTimeout(() => { - const allGrids = container.querySelectorAll('swp-grid-container'); - // Keep only the newest grid (last one), remove all others - for (let i = 0; i < allGrids.length - 1; i++) { - allGrids[i].remove(); - } - }, 450); + // Update state + this.currentWeek = new Date(targetWeek); + this.animationQueue--; - // Slide in new grid - newGrid.style.transform = 'translateX(0)'; + // If this was the last queued animation, ensure we're in sync + if (this.animationQueue === 0) { + this.currentWeek = new Date(this.targetWeek); + } - // Wait for new grid animation to complete before updating state - setTimeout(() => { - newGrid.style.position = 'relative'; - - // Only now is the animation truly complete - this.currentWeek = new Date(targetWeek); - this.animationQueue--; - - // If this was the last queued animation, ensure we're in sync - if (this.animationQueue === 0) { - this.currentWeek = new Date(this.targetWeek); - } - - // Update week info and notify other managers - this.updateWeekInfo(); - this.eventBus.emit(EventTypes.WEEK_CHANGED, { - weekStart: this.currentWeek, - weekEnd: DateUtils.addDays(this.currentWeek, 6) - }); - - console.log(`NavigationManager: Completed ${direction} animation`); - }, 400); // Wait for slide-in animation to complete + // Update week info and notify other managers + this.updateWeekInfo(); + this.eventBus.emit(EventTypes.WEEK_CHANGED, { + weekStart: this.currentWeek, + weekEnd: DateUtils.addDays(this.currentWeek, 6) + }); + + // Emit animation complete event for ScrollManager + this.eventBus.emit(EventTypes.NAVIGATION_ANIMATION_COMPLETE, { + direction, + weekStart: this.currentWeek + }); + + console.log(`NavigationManager: Completed ${direction} animation`); }); } diff --git a/src/managers/ScrollManager.ts b/src/managers/ScrollManager.ts index 8d807af..aa53a5e 100644 --- a/src/managers/ScrollManager.ts +++ b/src/managers/ScrollManager.ts @@ -33,9 +33,13 @@ export class ScrollManager { } private subscribeToEvents(): void { + // Handle navigation animation completion - sync time axis position + eventBus.on(EventTypes.NAVIGATION_ANIMATION_COMPLETE, () => { + console.log('ScrollManager: Navigation animation complete'); + this.syncTimeAxisPosition(); + this.setupScrolling(); + }); - // Handle new period shown - //we need to subscribe to appropriate event and then call setupScrolling() again // Handle window resize window.addEventListener('resize', () => {