11import React , { useEffect , useState } from 'react' ;
2- import { FaInbox , FaFileExcel , FaPencilAlt , FaUtensils , FaPaintBrush , FaBriefcase } from 'react-icons/fa' ;
2+ import {
3+ FaInbox ,
4+ FaFileExcel ,
5+ FaPencilAlt ,
6+ FaUtensils ,
7+ FaPaintBrush ,
8+ FaBriefcase ,
9+ } from 'react-icons/fa' ;
310
411/* ──────── GIF imports ──────── */
512import inboxclipGif from './gifs/inboxclips.gif' ;
613import excelclipGif from './gifs/excelclip.gif' ;
714import essayclipGif from './gifs/essayclip.gif' ;
815import lunchclipGif from './gifs/lunchclip.gif' ;
916import figmaclipGif from './gifs/figmaclip.gif' ;
10- import jobclipGif from './gifs/jobclip.gif' ;
17+ import jobclipGif from './gifs/jobclip.gif' ;
1118
1219const gifMap = {
1320 'inboxclips.gif' : inboxclipGif ,
14- 'excelclip.gif' : excelclipGif ,
15- 'essayclip.gif' : essayclipGif ,
16- 'lunchclip.gif' : lunchclipGif ,
17- 'figmaclip.gif' : figmaclipGif ,
18- 'jobclip.gif' : jobclipGif ,
21+ 'excelclip.gif' : excelclipGif ,
22+ 'essayclip.gif' : essayclipGif ,
23+ 'lunchclip.gif' : lunchclipGif ,
24+ 'figmaclip.gif' : figmaclipGif ,
25+ 'jobclip.gif' : jobclipGif ,
1926} ;
2027
2128const sliderIcons = [
@@ -33,29 +40,37 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
3340 const [ isDragging , setIsDragging ] = useState ( false ) ;
3441
3542 useEffect ( ( ) => {
36- const handleMove = clientX => {
43+ const handleMove = ( clientX ) => {
3744 if ( ! isDragging || ! sliderRef . current ) return ;
3845 const { left, width } = sliderRef . current . getBoundingClientRect ( ) ;
3946 const clampedX = Math . max ( 0 , Math . min ( clientX - left , width ) ) ;
4047 const ratio = clampedX / width ;
41- const newValue = Math . round ( ( min + ratio * ( max - min ) ) / step ) * step ;
48+ const newValue =
49+ Math . round ( ( min + ratio * ( max - min ) ) / step ) * step ;
4250 onChange ( newValue ) ;
4351 } ;
4452
45- const mouse = e => handleMove ( e . clientX ) ;
46- const touch = e => e . touches [ 0 ] && handleMove ( e . touches [ 0 ] . clientX ) ;
53+ const mouse = ( e ) => handleMove ( e . clientX ) ;
54+
55+ const touch = ( e ) => {
56+ if ( isDragging ) e . preventDefault ( ) ; // prevent pull-to-refresh
57+ if ( e . touches [ 0 ] ) handleMove ( e . touches [ 0 ] . clientX ) ;
58+ } ;
59+
4760 const endDrag = ( ) => setIsDragging ( false ) ;
4861
4962 window . addEventListener ( 'mousemove' , mouse ) ;
50- window . addEventListener ( 'mouseup' , endDrag ) ;
51- window . addEventListener ( 'touchmove' , touch ) ;
52- window . addEventListener ( 'touchend' , endDrag ) ;
63+ window . addEventListener ( 'mouseup' , endDrag ) ;
64+ // ⚠️ non-passive listener so preventDefault works on iOS
65+ window . addEventListener ( 'touchmove' , touch , { passive : false } ) ;
66+ window . addEventListener ( 'touchend' , endDrag ) ;
5367 window . addEventListener ( 'touchcancel' , endDrag ) ;
68+
5469 return ( ) => {
5570 window . removeEventListener ( 'mousemove' , mouse ) ;
56- window . removeEventListener ( 'mouseup' , endDrag ) ;
57- window . removeEventListener ( 'touchmove' , touch ) ;
58- window . removeEventListener ( 'touchend' , endDrag ) ;
71+ window . removeEventListener ( 'mouseup' , endDrag ) ;
72+ window . removeEventListener ( 'touchmove' , touch , { passive : false } ) ;
73+ window . removeEventListener ( 'touchend' , endDrag ) ;
5974 window . removeEventListener ( 'touchcancel' , endDrag ) ;
6075 } ;
6176 } , [ isDragging , min , max , step , onChange ] ) ;
@@ -64,27 +79,75 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
6479 const iconSize = 20 ; // Size of the icon for positioning calculations
6580
6681 return (
67- < div style = { { position : 'relative' , width : '100%' , height : 40 /* Increased height for icons */ } } >
68- < div ref = { sliderRef } style = { { position :'relative' , width :'100%' , height :20 , marginTop : 15 /* Make space for icons above */ } } >
69- < div style = { {
70- position :'absolute' , top :'50%' , left :0 , transform :'translateY(-50%)' ,
71- width :'100%' , height :4 , background :'rgba(214,206,186,.3)' , borderRadius :2
72- } } />
73- < div style = { {
74- position :'absolute' , top :'50%' , left :0 , transform :'translateY(-50%)' ,
75- width :`${ ratio * 100 } %` , height :4 , background :'#d6ceba' , borderRadius :2
76- } } />
82+ < div
83+ style = { {
84+ position : 'relative' ,
85+ width : '100%' ,
86+ height : 40 /* Increased height for icons */ ,
87+ } }
88+ >
89+ < div
90+ ref = { sliderRef }
91+ style = { {
92+ position : 'relative' ,
93+ width : '100%' ,
94+ height : 20 ,
95+ marginTop : 15 /* Make space for icons above */ ,
96+ } }
97+ >
98+ < div
99+ style = { {
100+ position : 'absolute' ,
101+ top : '50%' ,
102+ left : 0 ,
103+ transform : 'translateY(-50%)' ,
104+ width : '100%' ,
105+ height : 4 ,
106+ background : 'rgba(214,206,186,.3)' ,
107+ borderRadius : 2 ,
108+ } }
109+ />
77110 < div
78- onMouseDown = { e => { e . preventDefault ( ) ; setIsDragging ( true ) ; } }
111+ style = { {
112+ position : 'absolute' ,
113+ top : '50%' ,
114+ left : 0 ,
115+ transform : 'translateY(-50%)' ,
116+ width : `${ ratio * 100 } %` ,
117+ height : 4 ,
118+ background : '#d6ceba' ,
119+ borderRadius : 2 ,
120+ } }
121+ />
122+ < div
123+ onMouseDown = { ( e ) => {
124+ e . preventDefault ( ) ;
125+ setIsDragging ( true ) ;
126+ } }
79127 onTouchStart = { ( ) => setIsDragging ( true ) }
80128 style = { {
81- position :'absolute' , top :'50%' , left :`calc(${ ratio * 100 } % - 10px)` ,
82- transform :'translateY(-50%)' , width :20 , height :20 , borderRadius :'50%' ,
83- background :'#d6ceba' , cursor :'pointer' , zIndex : 2
129+ position : 'absolute' ,
130+ top : '50%' ,
131+ left : `calc(${ ratio * 100 } % - 10px)` ,
132+ transform : 'translateY(-50%)' ,
133+ width : 20 ,
134+ height : 20 ,
135+ borderRadius : '50%' ,
136+ background : '#d6ceba' ,
137+ cursor : 'pointer' ,
138+ zIndex : 2 ,
84139 } }
85140 />
86141 </ div >
87- < div style = { { display : 'flex' , justifyContent : 'space-between' , width : '100%' , position : 'absolute' , top : 0 } } >
142+ < div
143+ style = { {
144+ display : 'flex' ,
145+ justifyContent : 'space-between' ,
146+ width : '100%' ,
147+ position : 'absolute' ,
148+ top : 0 ,
149+ } }
150+ >
88151 { icons . map ( ( iconData ) => {
89152 const IconComponent = iconData . icon ;
90153 const iconRatio = ( iconData . value - min ) / ( max - min ) ;
@@ -100,10 +163,15 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
100163 transform : 'translateY(-50%)' ,
101164 cursor : 'pointer' ,
102165 zIndex : 1 ,
103- color : isActive ? '#d6ceba' : 'rgba(214,206,186,.5)' ,
104- fontSize : `${ iconSize } px`
166+ color : isActive
167+ ? '#d6ceba'
168+ : 'rgba(214,206,186,.5)' ,
169+ fontSize : `${ iconSize } px` ,
105170 } }
106- title = { iconData . key . charAt ( 0 ) . toUpperCase ( ) + iconData . key . slice ( 1 ) } // Tooltip for accessibility
171+ title = {
172+ iconData . key . charAt ( 0 ) . toUpperCase ( ) +
173+ iconData . key . slice ( 1 )
174+ } // Tooltip for accessibility
107175 >
108176 < IconComponent />
109177 </ div >
@@ -116,24 +184,41 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
116184
117185/* ──────── Left Pane ──────── */
118186const LeftPane = ( { selectedHour, onTimeChange, activity, gif } ) => {
119- const gifSrc = gifMap [ gif ] || inboxclipGif ; // fallback to inbox clip
187+ const gifSrc = gifMap [ gif ] || inboxclipGif ; // fallback to inbox clip
120188
121189 return (
122190 < div className = "leftpane-container" >
123191 { /* Activity clip */ }
124- < div style = { { width :'100%' } } >
192+ < div style = { { width : '100%' } } >
125193 < img
126194 src = { gifSrc }
127195 alt = { activity }
128- style = { { width :'100%' , height :'auto' , objectFit :'contain' , display :'block' , margin : '0 auto' } }
196+ style = { {
197+ width : '100%' ,
198+ height : 'auto' ,
199+ objectFit : 'contain' ,
200+ display : 'block' ,
201+ margin : '0 auto' ,
202+ } }
129203 />
130- < p style = { { margin :'15px 0 15px' , fontSize :16 } } > < b > { activity } </ b > </ p >
204+ < p style = { { margin : '15px 0 15px' , fontSize : 16 } } >
205+ < b > { activity } </ b >
206+ </ p >
131207 </ div >
132208
133209 { /* Hour selector */ }
134- < div style = { { width :200 , margin :'0 auto' } } >
135- < div style = { { display :'flex' , alignItems :'center' , gap :20 } } >
136- < FancySlider min = { 1 } max = { 6 } step = { 1 } value = { selectedHour } onChange = { onTimeChange } icons = { sliderIcons } />
210+ < div style = { { width : 200 , margin : '0 auto' } } >
211+ < div
212+ style = { { display : 'flex' , alignItems : 'center' , gap : 20 } }
213+ >
214+ < FancySlider
215+ min = { 1 }
216+ max = { 6 }
217+ step = { 1 }
218+ value = { selectedHour }
219+ onChange = { onTimeChange }
220+ icons = { sliderIcons }
221+ />
137222 </ div >
138223 </ div >
139224 </ div >
0 commit comments