Skip to content

Commit eff33b2

Browse files
committed
attempt 2 mobile refresh bug fix
1 parent 7b01df3 commit eff33b2

File tree

2 files changed

+78
-87
lines changed

2 files changed

+78
-87
lines changed

src/components/Carousel.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const AnimatedRow = forwardRef(({ row, rowIndex }, rowContainerRef) => (
5858
alignItems: 'center',
5959
backgroundColor: 'var(--color-main-text)',
6060
borderRadius: '8px',
61-
padding: '12px 0 6px 12px',
61+
padding: '10px 0 6px 12px',
6262
height: '60px',
6363
boxSizing: 'border-box',
6464
}}
@@ -131,7 +131,7 @@ const AnimatedRow = forwardRef(({ row, rowIndex }, rowContainerRef) => (
131131
alignItems: 'center',
132132
backgroundColor: 'var(--color-main-text)',
133133
borderRadius: '8px',
134-
padding: '12px 0 6px 12px',
134+
padding: '10px 0 6px 12px',
135135
height: '60px',
136136
boxSizing: 'border-box',
137137
}}
@@ -207,7 +207,7 @@ const Carousel = ({ carouselData }) => {
207207
/* 3️⃣ Duration: unchanged for >1000 px; slower formula for <1000 px */
208208
let animationDuration = Math.max(8, screenWidth / 80); // original rule
209209
if (screenWidth < 1000 && rowWidth) {
210-
animationDuration = Math.max(12, rowWidth / 80); // ⇢ slower
210+
animationDuration = Math.max(20, rowWidth / 80); // ⇢ slower
211211
}
212212

213213
return (

src/components/LeftPane.jsx

Lines changed: 75 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { useEffect, useRef, useState } from 'react';
22
import {
33
FaInbox,
44
FaFileExcel,
@@ -14,85 +14,85 @@ import excelclipGif from './gifs/excelclip.gif';
1414
import essayclipGif from './gifs/essayclip.gif';
1515
import lunchclipGif from './gifs/lunchclip.gif';
1616
import figmaclipGif from './gifs/figmaclip.gif';
17-
import jobclipGif from './gifs/jobclip.gif';
17+
import jobclipGif from './gifs/jobclip.gif';
1818

1919
const gifMap = {
2020
'inboxclips.gif': inboxclipGif,
21-
'excelclip.gif': excelclipGif,
22-
'essayclip.gif': essayclipGif,
23-
'lunchclip.gif': lunchclipGif,
24-
'figmaclip.gif': figmaclipGif,
25-
'jobclip.gif': jobclipGif,
21+
'excelclip.gif' : excelclipGif,
22+
'essayclip.gif' : essayclipGif,
23+
'lunchclip.gif' : lunchclipGif,
24+
'figmaclip.gif' : figmaclipGif,
25+
'jobclip.gif' : jobclipGif,
2626
};
2727

2828
const sliderIcons = [
29-
{ icon: FaInbox, value: 1, key: 'inbox' },
30-
{ icon: FaFileExcel, value: 2, key: 'excel' },
31-
{ icon: FaPencilAlt, value: 3, key: 'essay' },
32-
{ icon: FaUtensils, value: 4, key: 'lunch' },
29+
{ icon: FaInbox, value: 1, key: 'inbox' },
30+
{ icon: FaFileExcel, value: 2, key: 'excel' },
31+
{ icon: FaPencilAlt, value: 3, key: 'essay' },
32+
{ icon: FaUtensils, value: 4, key: 'lunch' },
3333
{ icon: FaPaintBrush, value: 5, key: 'figma' },
34-
{ icon: FaBriefcase, value: 6, key: 'job' },
34+
{ icon: FaBriefcase, value: 6, key: 'job' },
3535
];
3636

3737
/* ──────── Slider ──────── */
3838
function FancySlider({ min, max, step, value, onChange, icons }) {
39-
const sliderRef = React.useRef(null);
40-
const [isDragging, setIsDragging] = useState(false);
39+
const trackRef = useRef(null);
40+
const [dragging, setDragging] = useState(false);
4141

42+
/* -------- pointer handlers -------- */
4243
useEffect(() => {
43-
const handleMove = (clientX) => {
44-
if (!isDragging || !sliderRef.current) return;
45-
const { left, width } = sliderRef.current.getBoundingClientRect();
46-
const clampedX = Math.max(0, Math.min(clientX - left, width));
47-
const ratio = clampedX / width;
48-
const newValue =
49-
Math.round((min + ratio * (max - min)) / step) * step;
50-
onChange(newValue);
44+
const track = trackRef.current;
45+
if (!track) return;
46+
47+
const move = (clientX) => {
48+
const { left, width } = track.getBoundingClientRect();
49+
const clamped = Math.max(0, Math.min(clientX - left, width));
50+
const ratio = clamped / width;
51+
const newVal = Math.round((min + ratio * (max - min)) / step) * step;
52+
if (newVal !== value) onChange(newVal);
5153
};
5254

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);
55+
const handlePointerMove = (e) => {
56+
if (!dragging) return;
57+
e.preventDefault();
58+
move(e.clientX);
5859
};
5960

60-
const endDrag = () => setIsDragging(false);
61+
const handlePointerUp = () => setDragging(false);
6162

62-
window.addEventListener('mousemove', mouse);
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);
67-
window.addEventListener('touchcancel', endDrag);
63+
window.addEventListener('pointermove', handlePointerMove);
64+
window.addEventListener('pointerup', handlePointerUp);
6865

6966
return () => {
70-
window.removeEventListener('mousemove', mouse);
71-
window.removeEventListener('mouseup', endDrag);
72-
window.removeEventListener('touchmove', touch, { passive: false });
73-
window.removeEventListener('touchend', endDrag);
74-
window.removeEventListener('touchcancel', endDrag);
67+
window.removeEventListener('pointermove', handlePointerMove);
68+
window.removeEventListener('pointerup', handlePointerUp);
7569
};
76-
}, [isDragging, min, max, step, onChange]);
70+
}, [dragging, min, max, step, onChange, value]);
7771

78-
const ratio = (value - min) / (max - min);
79-
const iconSize = 20; // Size of the icon for positioning calculations
72+
/* -------- slider visuals -------- */
73+
const ratio = (value - min) / (max - min);
74+
const iconSize = 20;
8075

8176
return (
8277
<div
83-
style={{
84-
position: 'relative',
85-
width: '100%',
86-
height: 40 /* Increased height for icons */,
87-
}}
78+
style={{ position: 'relative', width: '100%', height: 40 }}
8879
>
80+
{/* TRACK */}
8981
<div
90-
ref={sliderRef}
82+
ref={trackRef}
9183
style={{
9284
position: 'relative',
9385
width: '100%',
9486
height: 20,
95-
marginTop: 15 /* Make space for icons above */,
87+
marginTop: 15,
88+
touchAction: 'none', // disable browser gestures
89+
overscrollBehaviorY: 'contain'
90+
}}
91+
onPointerDown={(e) => {
92+
setDragging(true);
93+
e.target.setPointerCapture(e.pointerId);
94+
e.preventDefault();
95+
move(e.clientX);
9696
}}
9797
>
9898
<div
@@ -120,11 +120,6 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
120120
}}
121121
/>
122122
<div
123-
onMouseDown={(e) => {
124-
e.preventDefault();
125-
setIsDragging(true);
126-
}}
127-
onTouchStart={() => setIsDragging(true)}
128123
style={{
129124
position: 'absolute',
130125
top: '50%',
@@ -139,41 +134,41 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
139134
}}
140135
/>
141136
</div>
137+
138+
{/* ICONS */}
142139
<div
143140
style={{
144141
display: 'flex',
145142
justifyContent: 'space-between',
146143
width: '100%',
147144
position: 'absolute',
148145
top: 0,
146+
pointerEvents: 'none', // icons themselves don’t intercept drag
149147
}}
150148
>
151-
{icons.map((iconData) => {
152-
const IconComponent = iconData.icon;
153-
const iconRatio = (iconData.value - min) / (max - min);
154-
const isActive = iconData.value === value;
149+
{icons.map(({ icon: Icon, value: v, key }) => {
150+
const iconRatio = (v - min) / (max - min);
151+
const active = v === value;
155152
return (
156153
<div
157-
key={iconData.key}
158-
onClick={() => onChange(iconData.value)}
154+
key={key}
155+
onPointerDown={(e) => { // allow tap-to-jump
156+
e.preventDefault();
157+
onChange(v);
158+
}}
159159
style={{
160160
position: 'absolute',
161161
left: `calc(${iconRatio * 100}% - ${iconSize / 2}px)`,
162162
top: '50%',
163163
transform: 'translateY(-50%)',
164+
fontSize: iconSize,
165+
color: active ? '#d6ceba' : 'rgba(214,206,186,.5)',
164166
cursor: 'pointer',
165-
zIndex: 1,
166-
color: isActive
167-
? '#d6ceba'
168-
: 'rgba(214,206,186,.5)',
169-
fontSize: `${iconSize}px`,
167+
pointerEvents: 'auto',
170168
}}
171-
title={
172-
iconData.key.charAt(0).toUpperCase() +
173-
iconData.key.slice(1)
174-
} // Tooltip for accessibility
169+
title={key.charAt(0).toUpperCase() + key.slice(1)}
175170
>
176-
<IconComponent />
171+
<Icon />
177172
</div>
178173
);
179174
})}
@@ -184,7 +179,7 @@ function FancySlider({ min, max, step, value, onChange, icons }) {
184179

185180
/* ──────── Left Pane ──────── */
186181
const LeftPane = ({ selectedHour, onTimeChange, activity, gif }) => {
187-
const gifSrc = gifMap[gif] || inboxclipGif; // fallback to inbox clip
182+
const gifSrc = gifMap[gif] || inboxclipGif; // fallback
188183

189184
return (
190185
<div className="leftpane-container">
@@ -201,25 +196,21 @@ const LeftPane = ({ selectedHour, onTimeChange, activity, gif }) => {
201196
margin: '0 auto',
202197
}}
203198
/>
204-
<p style={{ margin: '15px 0 15px', fontSize: 16 }}>
199+
<p style={{ margin: '15px 0', fontSize: 16 }}>
205200
<b>{activity}</b>
206201
</p>
207202
</div>
208203

209204
{/* Hour selector */}
210205
<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-
/>
222-
</div>
206+
<FancySlider
207+
min={1}
208+
max={6}
209+
step={1}
210+
value={selectedHour}
211+
onChange={onTimeChange}
212+
icons={sliderIcons}
213+
/>
223214
</div>
224215
</div>
225216
);

0 commit comments

Comments
 (0)