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.
This commit is contained in:
Janus Knudsen 2025-08-13 23:37:23 +02:00
parent b03707853a
commit afe5b6b899
3 changed files with 57 additions and 39 deletions

View file

@ -25,6 +25,7 @@ export const EventTypes = {
WEEK_CHANGED: 'calendar:weekchanged', WEEK_CHANGED: 'calendar:weekchanged',
WEEK_INFO_UPDATED: 'calendar:weekinfoupdated', WEEK_INFO_UPDATED: 'calendar:weekinfoupdated',
WEEK_CONTENT_RENDERED: 'calendar:weekcontentrendered', WEEK_CONTENT_RENDERED: 'calendar:weekcontentrendered',
NAVIGATION_ANIMATION_COMPLETE: 'calendar:navigationanimationcomplete',
NAV_PREV: 'calendar:navprev', NAV_PREV: 'calendar:navprev',
NAV_NEXT: 'calendar:navnext', NAV_NEXT: 'calendar:navnext',
NAV_TODAY: 'calendar:navtoday', NAV_TODAY: 'calendar:navtoday',

View file

@ -152,46 +152,59 @@ export class NavigationManager {
// Render new content for target week // Render new content for target week
this.renderWeekContent(newGrid, targetWeek); this.renderWeekContent(newGrid, targetWeek);
// Animate transition (POC animation) // Animate transition using Web Animations API
requestAnimationFrame(() => { const slideOutAnimation = (currentGrid as HTMLElement).animate([
// Slide out current grid { transform: 'translateX(0)', opacity: '1' },
(currentGrid as HTMLElement).style.transform = direction === 'next' ? 'translateX(-100%)' : 'translateX(100%)'; { transform: direction === 'next' ? 'translateX(-100%)' : 'translateX(100%)', opacity: '0.5' }
(currentGrid as HTMLElement).style.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 // Update state
setTimeout(() => { this.currentWeek = new Date(targetWeek);
const allGrids = container.querySelectorAll('swp-grid-container'); this.animationQueue--;
// Keep only the newest grid (last one), remove all others
for (let i = 0; i < allGrids.length - 1; i++) {
allGrids[i].remove();
}
}, 450);
// Slide in new grid // If this was the last queued animation, ensure we're in sync
newGrid.style.transform = 'translateX(0)'; if (this.animationQueue === 0) {
this.currentWeek = new Date(this.targetWeek);
}
// Wait for new grid animation to complete before updating state // Update week info and notify other managers
setTimeout(() => { this.updateWeekInfo();
newGrid.style.position = 'relative'; this.eventBus.emit(EventTypes.WEEK_CHANGED, {
weekStart: this.currentWeek,
// Only now is the animation truly complete weekEnd: DateUtils.addDays(this.currentWeek, 6)
this.currentWeek = new Date(targetWeek); });
this.animationQueue--;
// Emit animation complete event for ScrollManager
// If this was the last queued animation, ensure we're in sync this.eventBus.emit(EventTypes.NAVIGATION_ANIMATION_COMPLETE, {
if (this.animationQueue === 0) { direction,
this.currentWeek = new Date(this.targetWeek); weekStart: this.currentWeek
} });
// Update week info and notify other managers console.log(`NavigationManager: Completed ${direction} animation`);
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
}); });
} }

View file

@ -33,9 +33,13 @@ export class ScrollManager {
} }
private subscribeToEvents(): void { 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 // Handle window resize
window.addEventListener('resize', () => { window.addEventListener('resize', () => {