1
1
import 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' ;
3
10
4
11
/* ──────── GIF imports ──────── */
5
12
import inboxclipGif from './gifs/inboxclips.gif' ;
6
13
import excelclipGif from './gifs/excelclip.gif' ;
7
14
import essayclipGif from './gifs/essayclip.gif' ;
8
15
import lunchclipGif from './gifs/lunchclip.gif' ;
9
16
import figmaclipGif from './gifs/figmaclip.gif' ;
10
- import jobclipGif from './gifs/jobclip.gif' ;
17
+ import jobclipGif from './gifs/jobclip.gif' ;
11
18
12
19
const gifMap = {
13
20
'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 ,
19
26
} ;
20
27
21
28
const sliderIcons = [
@@ -33,29 +40,37 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
33
40
const [ isDragging , setIsDragging ] = useState ( false ) ;
34
41
35
42
useEffect ( ( ) => {
36
- const handleMove = clientX => {
43
+ const handleMove = ( clientX ) => {
37
44
if ( ! isDragging || ! sliderRef . current ) return ;
38
45
const { left, width } = sliderRef . current . getBoundingClientRect ( ) ;
39
46
const clampedX = Math . max ( 0 , Math . min ( clientX - left , width ) ) ;
40
47
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 ;
42
50
onChange ( newValue ) ;
43
51
} ;
44
52
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
+
47
60
const endDrag = ( ) => setIsDragging ( false ) ;
48
61
49
62
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 ) ;
53
67
window . addEventListener ( 'touchcancel' , endDrag ) ;
68
+
54
69
return ( ) => {
55
70
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 ) ;
59
74
window . removeEventListener ( 'touchcancel' , endDrag ) ;
60
75
} ;
61
76
} , [ isDragging , min , max , step , onChange ] ) ;
@@ -64,27 +79,75 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
64
79
const iconSize = 20 ; // Size of the icon for positioning calculations
65
80
66
81
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
+ />
77
110
< 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
+ } }
79
127
onTouchStart = { ( ) => setIsDragging ( true ) }
80
128
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 ,
84
139
} }
85
140
/>
86
141
</ 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
+ >
88
151
{ icons . map ( ( iconData ) => {
89
152
const IconComponent = iconData . icon ;
90
153
const iconRatio = ( iconData . value - min ) / ( max - min ) ;
@@ -100,10 +163,15 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
100
163
transform : 'translateY(-50%)' ,
101
164
cursor : 'pointer' ,
102
165
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` ,
105
170
} }
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
107
175
>
108
176
< IconComponent />
109
177
</ div >
@@ -116,24 +184,41 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
116
184
117
185
/* ──────── Left Pane ──────── */
118
186
const 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
120
188
121
189
return (
122
190
< div className = "leftpane-container" >
123
191
{ /* Activity clip */ }
124
- < div style = { { width :'100%' } } >
192
+ < div style = { { width : '100%' } } >
125
193
< img
126
194
src = { gifSrc }
127
195
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
+ } }
129
203
/>
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 >
131
207
</ div >
132
208
133
209
{ /* 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
+ />
137
222
</ div >
138
223
</ div >
139
224
</ div >
0 commit comments