@@ -183,7 +183,7 @@ function renderContent() {
183183}
184184
185185// Navigate to chapter with animation
186- function navigateToChapter ( newIndex ) {
186+ function navigateToChapter ( newIndex , interactionMethod = 'click' ) {
187187 if ( isTransitioning || newIndex === activeChapter ) return ;
188188
189189 // Hide the hint after first navigation
@@ -194,6 +194,19 @@ function navigateToChapter(newIndex) {
194194
195195 isTransitioning = true ;
196196 const direction = newIndex > activeChapter ? 'next' : 'prev' ;
197+
198+ // Track timeline navigation with Google Analytics
199+ if ( typeof gtag !== 'undefined' ) {
200+ const chapterName = chapters [ newIndex ] ?. title || `Chapter ${ newIndex } ` ;
201+ gtag ( 'event' , 'timeline_navigation' , {
202+ event_category : 'Timeline' ,
203+ event_label : chapterName ,
204+ chapter_index : newIndex ,
205+ direction : direction ,
206+ previous_chapter : activeChapter ,
207+ interaction_method : interactionMethod
208+ } ) ;
209+ }
197210
198211 // Calculate timeline position
199212 const timelineElement = document . querySelector ( '.timeline-section' ) ;
@@ -260,11 +273,11 @@ function navigateToChapter(newIndex) {
260273}
261274
262275// Navigate with buttons
263- function navigate ( direction ) {
276+ function navigate ( direction , interactionMethod = 'button' ) {
264277 const newIndex = direction === 'next'
265278 ? Math . min ( activeChapter + 1 , chapters . length - 1 )
266279 : Math . max ( activeChapter - 1 , 0 ) ;
267- navigateToChapter ( newIndex ) ;
280+ navigateToChapter ( newIndex , interactionMethod ) ;
268281}
269282
270283// Initialize event listeners
@@ -285,10 +298,13 @@ function initEventListeners() {
285298
286299 // Keyboard navigation
287300 document . addEventListener ( 'keydown' , ( e ) => {
288- if ( e . key === 'ArrowLeft' ) navigate ( 'prev' ) ;
289- if ( e . key === 'ArrowRight' ) navigate ( 'next' ) ;
301+ if ( e . key === 'ArrowLeft' ) navigate ( 'prev' , 'keyboard' ) ;
302+ if ( e . key === 'ArrowRight' ) navigate ( 'next' , 'keyboard' ) ;
290303 } ) ;
291304
305+ // Touch gesture navigation
306+ initTouchGestures ( ) ;
307+
292308 // Handle resize
293309 let resizeTimeout ;
294310 window . addEventListener ( 'resize' , ( ) => {
@@ -299,6 +315,54 @@ function initEventListeners() {
299315 } ) ;
300316}
301317
318+ // Touch gesture support
319+ function initTouchGestures ( ) {
320+ if ( ! timelineSection ) return ;
321+
322+ let touchStartX = 0 ;
323+ let touchStartY = 0 ;
324+ let touchEndX = 0 ;
325+ let touchEndY = 0 ;
326+
327+ // Minimum distance for a swipe to register (in pixels)
328+ const minSwipeDistance = 50 ;
329+ // Maximum vertical movement allowed for horizontal swipe
330+ const maxVerticalDeviation = 100 ;
331+
332+ // Touch start
333+ timelineSection . addEventListener ( 'touchstart' , ( e ) => {
334+ touchStartX = e . touches [ 0 ] . clientX ;
335+ touchStartY = e . touches [ 0 ] . clientY ;
336+ } , { passive : true } ) ;
337+
338+ // Touch end
339+ timelineSection . addEventListener ( 'touchend' , ( e ) => {
340+ touchEndX = e . changedTouches [ 0 ] . clientX ;
341+ touchEndY = e . changedTouches [ 0 ] . clientY ;
342+ handleSwipe ( ) ;
343+ } , { passive : true } ) ;
344+
345+ // Handle swipe gesture
346+ function handleSwipe ( ) {
347+ const deltaX = touchEndX - touchStartX ;
348+ const deltaY = Math . abs ( touchEndY - touchStartY ) ;
349+
350+ // Check if this was primarily a horizontal swipe
351+ if ( Math . abs ( deltaX ) > minSwipeDistance && deltaY < maxVerticalDeviation ) {
352+ // Prevent navigation if already transitioning
353+ if ( isTransitioning ) return ;
354+
355+ // Swipe right (positive deltaX) = go to previous chapter
356+ // Swipe left (negative deltaX) = go to next chapter
357+ if ( deltaX > 0 ) {
358+ navigate ( 'prev' , 'swipe' ) ;
359+ } else {
360+ navigate ( 'next' , 'swipe' ) ;
361+ }
362+ }
363+ }
364+ }
365+
302366// Main initialization function
303367export function initTimelineComponent ( ) {
304368 console . log ( 'Initializing timeline component...' ) ;
0 commit comments