1- import { createContext , useContext , useEffect , useRef , ReactNode } from 'react' ;
1+ import { createContext , useContext , useEffect , useRef , ReactNode , useState } from 'react' ;
22import LocomotiveScroll from 'locomotive-scroll' ;
33import 'locomotive-scroll/dist/locomotive-scroll.css' ;
44
55interface SmoothScrollContextType {
66 locomotiveScroll : LocomotiveScroll | null ;
7+ currentSection : number ;
8+ totalSections : number ;
9+ scrollToSection : ( index : number ) => void ;
10+ scrollToNextSection : ( ) => void ;
11+ scrollToPrevSection : ( ) => void ;
712}
813
914const SmoothScrollContext = createContext < SmoothScrollContextType > ( {
@@ -18,96 +23,138 @@ interface SmoothScrollProviderProps {
1823
1924export function SmoothScrollProvider ( { children } : SmoothScrollProviderProps ) {
2025 const locomotiveScrollRef = useRef < LocomotiveScroll | null > ( null ) ;
26+ const [ currentSection , setCurrentSection ] = useState ( 0 ) ;
27+ const [ totalSections , setTotalSections ] = useState ( 0 ) ;
28+
29+
2130
2231 useEffect ( ( ) => {
2332 // Initialize Locomotive Scroll
2433 locomotiveScrollRef . current = new LocomotiveScroll ( {
2534 el : document . querySelector ( '[data-scroll-container]' ) as HTMLElement ,
2635 smooth : true ,
27- lerp : 0.1 ,
36+ lerp : 0.08 , // Slightly faster for better responsiveness
2837 multiplier : 0.8 ,
29- // Enable snap scrolling to sections
38+ // Enhanced snap scrolling
3039 scrollFromAnywhere : true ,
31- // Snap to sections
3240 snap : true ,
33- // Snap duration
34- snapDuration : 1.2 ,
35- // Snap easing
41+ snapDuration : 1.5 , // Slightly longer for smoother transitions
3642 snapEasing : [ 0.25 , 0.1 , 0.25 , 1 ] ,
43+ // Better section detection
44+ offset : [ '0%' , '0%' ] ,
3745 smartphone : {
3846 smooth : true ,
39- lerp : 0.1 ,
47+ lerp : 0.08 ,
4048 multiplier : 0.8 ,
4149 snap : true ,
42- snapDuration : 1.2 ,
50+ snapDuration : 1.5 ,
4351 } ,
4452 tablet : {
4553 smooth : true ,
46- lerp : 0.1 ,
54+ lerp : 0.08 ,
4755 multiplier : 0.8 ,
4856 snap : true ,
49- snapDuration : 1.2 ,
57+ snapDuration : 1.5 ,
5058 } ,
5159 } ) ;
5260
53- // Add keyboard navigation
61+ // Get all sections for better navigation
62+ const sections = document . querySelectorAll ( '[data-scroll-section]' ) ;
63+ setTotalSections ( sections . length ) ;
64+
65+ // Enhanced keyboard navigation with section snapping
5466 const handleKeyDown = ( e : KeyboardEvent ) => {
5567 if ( ! locomotiveScrollRef . current ) return ;
5668
57- const windowHeight = window . innerHeight ;
58- const currentScrollY = locomotiveScrollRef . current . scroll . y ;
59- const currentSection = Math . round ( currentScrollY / windowHeight ) ;
60-
6169 switch ( e . key ) {
6270 case 'ArrowDown' :
6371 case 'PageDown' :
6472 case ' ' :
6573 e . preventDefault ( ) ;
66- const nextSection = Math . min ( currentSection + 1 , Math . floor ( document . body . scrollHeight / windowHeight ) - 1 ) ;
67- locomotiveScrollRef . current . scrollTo ( nextSection * windowHeight , {
68- duration : 1.2 ,
69- easing : [ 0.25 , 0.1 , 0.25 , 1 ] ,
70- } ) ;
74+ scrollToNextSection ( ) ;
7175 break ;
7276 case 'ArrowUp' :
7377 case 'PageUp' :
7478 e . preventDefault ( ) ;
75- const prevSection = Math . max ( currentSection - 1 , 0 ) ;
76- locomotiveScrollRef . current . scrollTo ( prevSection * windowHeight , {
77- duration : 1.2 ,
78- easing : [ 0.25 , 0.1 , 0.25 , 1 ] ,
79- } ) ;
79+ scrollToPrevSection ( ) ;
8080 break ;
8181 case 'Home' :
8282 e . preventDefault ( ) ;
83- locomotiveScrollRef . current . scrollTo ( 0 , {
84- duration : 1.2 ,
85- easing : [ 0.25 , 0.1 , 0.25 , 1 ] ,
86- } ) ;
83+ scrollToSection ( 0 ) ;
8784 break ;
8885 case 'End' :
8986 e . preventDefault ( ) ;
90- locomotiveScrollRef . current . scrollTo ( document . body . scrollHeight - windowHeight , {
91- duration : 1.2 ,
92- easing : [ 0.25 , 0.1 , 0.25 , 1 ] ,
93- } ) ;
87+ scrollToSection ( totalSections - 1 ) ;
9488 break ;
9589 }
9690 } ;
9791
92+ // Section navigation functions
93+ const scrollToSection = ( index : number ) => {
94+ if ( ! locomotiveScrollRef . current || index < 0 || index >= totalSections ) return ;
95+
96+ const sections = document . querySelectorAll ( '[data-scroll-section]' ) ;
97+ const targetSection = sections [ index ] as HTMLElement ;
98+
99+ if ( targetSection ) {
100+ locomotiveScrollRef . current . scrollTo ( targetSection , {
101+ duration : 1.5 ,
102+ easing : [ 0.25 , 0.1 , 0.25 , 1 ] ,
103+ } ) ;
104+ setCurrentSection ( index ) ;
105+ }
106+ } ;
107+
108+ const scrollToNextSection = ( ) => {
109+ const nextSection = Math . min ( currentSection + 1 , totalSections - 1 ) ;
110+ scrollToSection ( nextSection ) ;
111+ } ;
112+
113+ const scrollToPrevSection = ( ) => {
114+ const prevSection = Math . max ( currentSection - 1 , 0 ) ;
115+ scrollToSection ( prevSection ) ;
116+ } ;
117+
118+ // Track current section on scroll
119+ const handleScroll = ( ) => {
120+ if ( ! locomotiveScrollRef . current ) return ;
121+
122+ const scrollY = locomotiveScrollRef . current . scroll . y ;
123+ const windowHeight = window . innerHeight ;
124+
125+ // Find which section is currently in view
126+ sections . forEach ( ( section , index ) => {
127+ const rect = section . getBoundingClientRect ( ) ;
128+ if ( rect . top <= windowHeight / 2 && rect . bottom >= windowHeight / 2 ) {
129+ setCurrentSection ( index ) ;
130+ }
131+ } ) ;
132+ } ;
133+
134+ // Add scroll event listener
135+ locomotiveScrollRef . current . on ( 'scroll' , handleScroll ) ;
136+
98137 document . addEventListener ( 'keydown' , handleKeyDown ) ;
99138
100139 // Cleanup
101140 return ( ) => {
102141 if ( locomotiveScrollRef . current ) {
142+ locomotiveScrollRef . current . off ( 'scroll' , handleScroll ) ;
103143 locomotiveScrollRef . current . destroy ( ) ;
104144 }
105145 document . removeEventListener ( 'keydown' , handleKeyDown ) ;
106146 } ;
107- } , [ ] ) ;
147+ } , [ currentSection , totalSections ] ) ;
108148
109149 return (
110- < SmoothScrollContext . Provider value = { { locomotiveScroll : locomotiveScrollRef . current } } >
150+ < SmoothScrollContext . Provider value = { {
151+ locomotiveScroll : locomotiveScrollRef . current ,
152+ currentSection,
153+ totalSections,
154+ scrollToSection,
155+ scrollToNextSection,
156+ scrollToPrevSection
157+ } } >
111158 { children }
112159 </ SmoothScrollContext . Provider >
113160 ) ;
0 commit comments