|
1 | 1 | import React, { useEffect, useState } from 'react'; |
2 | 2 |
|
| 3 | +/* ──────── GIF imports ──────── */ |
| 4 | +import inboxclipGif from './gifs/inboxclips.gif'; |
| 5 | +import excelclipGif from './gifs/excelclip.gif'; |
| 6 | +import essayclipGif from './gifs/essayclip.gif'; |
| 7 | +import lunchclipGif from './gifs/lunchclip.gif'; |
| 8 | +import figmaclipGif from './gifs/figmaclip.gif'; |
| 9 | +import jobclipGif from './gifs/jobclip.gif'; |
| 10 | + |
| 11 | +const gifMap = { |
| 12 | + 'inboxclips.gif': inboxclipGif, |
| 13 | + 'excelclip.gif' : excelclipGif, |
| 14 | + 'essayclip.gif' : essayclipGif, |
| 15 | + 'lunchclip.gif' : lunchclipGif, |
| 16 | + 'figmaclip.gif' : figmaclipGif, |
| 17 | + 'jobclip.gif' : jobclipGif, |
| 18 | +}; |
| 19 | + |
| 20 | +/* ──────── Slider ──────── */ |
3 | 21 | function FancySlider({ min, max, step, value, onChange }) { |
4 | 22 | const sliderRef = React.useRef(null); |
5 | 23 | const [isDragging, setIsDragging] = useState(false); |
6 | 24 |
|
7 | 25 | useEffect(() => { |
8 | | - function handleMove(clientX) { |
| 26 | + const handleMove = clientX => { |
9 | 27 | if (!isDragging || !sliderRef.current) return; |
10 | | - const rect = sliderRef.current.getBoundingClientRect(); |
11 | | - const x = clientX - rect.left; |
12 | | - const clampedX = Math.max(0, Math.min(x, rect.width)); |
13 | | - const ratio = clampedX / rect.width; |
14 | | - let newValue = min + ratio * (max - min); |
15 | | - newValue = Math.round(newValue / step) * step; |
| 28 | + const { left, width } = sliderRef.current.getBoundingClientRect(); |
| 29 | + const clampedX = Math.max(0, Math.min(clientX - left, width)); |
| 30 | + const ratio = clampedX / width; |
| 31 | + const newValue = Math.round((min + ratio * (max - min)) / step) * step; |
16 | 32 | onChange(newValue); |
17 | | - } |
18 | | - |
19 | | - function handleMouseMove(e) { |
20 | | - handleMove(e.clientX); |
21 | | - } |
22 | | - |
23 | | - function handleTouchMove(e) { |
24 | | - if (e.touches && e.touches[0]) { |
25 | | - handleMove(e.touches[0].clientX); |
26 | | - } |
27 | | - } |
28 | | - |
29 | | - function handleEnd() { |
30 | | - setIsDragging(false); |
31 | | - } |
32 | | - |
33 | | - // Mouse events |
34 | | - window.addEventListener('mousemove', handleMouseMove); |
35 | | - window.addEventListener('mouseup', handleEnd); |
| 33 | + }; |
36 | 34 |
|
37 | | - // Touch events |
38 | | - window.addEventListener('touchmove', handleTouchMove); |
39 | | - window.addEventListener('touchend', handleEnd); |
40 | | - window.addEventListener('touchcancel', handleEnd); |
| 35 | + const mouse = e => handleMove(e.clientX); |
| 36 | + const touch = e => e.touches[0] && handleMove(e.touches[0].clientX); |
| 37 | + const endDrag = () => setIsDragging(false); |
41 | 38 |
|
| 39 | + window.addEventListener('mousemove', mouse); |
| 40 | + window.addEventListener('mouseup', endDrag); |
| 41 | + window.addEventListener('touchmove', touch); |
| 42 | + window.addEventListener('touchend', endDrag); |
| 43 | + window.addEventListener('touchcancel', endDrag); |
42 | 44 | return () => { |
43 | | - window.removeEventListener('mousemove', handleMouseMove); |
44 | | - window.removeEventListener('mouseup', handleEnd); |
45 | | - window.removeEventListener('touchmove', handleTouchMove); |
46 | | - window.removeEventListener('touchend', handleEnd); |
47 | | - window.removeEventListener('touchcancel', handleEnd); |
| 45 | + window.removeEventListener('mousemove', mouse); |
| 46 | + window.removeEventListener('mouseup', endDrag); |
| 47 | + window.removeEventListener('touchmove', touch); |
| 48 | + window.removeEventListener('touchend', endDrag); |
| 49 | + window.removeEventListener('touchcancel', endDrag); |
48 | 50 | }; |
49 | 51 | }, [isDragging, min, max, step, onChange]); |
50 | 52 |
|
51 | | - const startDrag = (e) => { |
52 | | - e.preventDefault(); |
53 | | - setIsDragging(true); |
54 | | - }; |
55 | | - |
56 | | - const startTouchDrag = (e) => { |
57 | | - setIsDragging(true); |
58 | | - }; |
59 | | - |
60 | 53 | const ratio = (value - min) / (max - min); |
61 | 54 |
|
62 | 55 | return ( |
63 | | - <div ref={sliderRef} style={{ position: 'relative', width: '100%', height: '20px' }}> |
| 56 | + <div ref={sliderRef} style={{ position:'relative', width:'100%', height:20 }}> |
| 57 | + <div style={{ |
| 58 | + position:'absolute', top:'50%', left:0, transform:'translateY(-50%)', |
| 59 | + width:'100%', height:4, background:'rgba(214,206,186,.3)', borderRadius:2 |
| 60 | + }}/> |
| 61 | + <div style={{ |
| 62 | + position:'absolute', top:'50%', left:0, transform:'translateY(-50%)', |
| 63 | + width:`${ratio*100}%`, height:4, background:'#d6ceba', borderRadius:2 |
| 64 | + }}/> |
64 | 65 | <div |
| 66 | + onMouseDown={e => { e.preventDefault(); setIsDragging(true); }} |
| 67 | + onTouchStart={() => setIsDragging(true)} |
65 | 68 | style={{ |
66 | | - position: 'absolute', |
67 | | - top: '50%', |
68 | | - left: 0, |
69 | | - transform: 'translateY(-50%)', |
70 | | - width: '100%', |
71 | | - height: '4px', |
72 | | - backgroundColor: 'rgba(214, 206, 186, 0.3)', |
73 | | - borderRadius: '2px', |
74 | | - }} |
75 | | - /> |
76 | | - <div |
77 | | - style={{ |
78 | | - position: 'absolute', |
79 | | - top: '50%', |
80 | | - left: 0, |
81 | | - transform: 'translateY(-50%)', |
82 | | - width: `${ratio * 100}%`, |
83 | | - height: '4px', |
84 | | - backgroundColor: '#d6ceba', |
85 | | - borderRadius: '2px', |
86 | | - }} |
87 | | - /> |
88 | | - <div |
89 | | - onMouseDown={startDrag} |
90 | | - onTouchStart={startTouchDrag} |
91 | | - style={{ |
92 | | - position: 'absolute', |
93 | | - top: '50%', |
94 | | - left: `calc(${ratio * 100}% - 10px)`, |
95 | | - transform: 'translateY(-50%)', |
96 | | - width: '20px', |
97 | | - height: '20px', |
98 | | - borderRadius: '50%', |
99 | | - backgroundColor: '#d6ceba', |
100 | | - cursor: 'pointer', |
| 69 | + position:'absolute', top:'50%', left:`calc(${ratio*100}% - 10px)`, |
| 70 | + transform:'translateY(-50%)', width:20, height:20, borderRadius:'50%', |
| 71 | + background:'#d6ceba', cursor:'pointer' |
101 | 72 | }} |
102 | 73 | /> |
103 | 74 | </div> |
104 | 75 | ); |
105 | 76 | } |
106 | 77 |
|
107 | | -const LeftPane = ({ selectedHour, onTimeChange, activity }) => { |
108 | | - const formatTime = (hour) => `Hour ${hour}`; |
109 | | - |
110 | | - const dividerStyle = { |
111 | | - width: '80%', |
112 | | - border: 'none', |
113 | | - borderTop: '1px solid #666', |
114 | | - }; |
| 78 | +/* ──────── Left Pane ──────── */ |
| 79 | +const LeftPane = ({ selectedHour, onTimeChange, activity, gif }) => { |
| 80 | + const gifSrc = gifMap[gif] || inboxclipGif; // fallback to inbox clip |
115 | 81 |
|
116 | 82 | return ( |
117 | 83 | <div |
118 | 84 | style={{ |
119 | | - display: 'flex', |
120 | | - flexDirection: 'column', |
121 | | - gap: '8px', |
122 | | - paddingTop: '24px', |
123 | | - paddingRight: '00px', |
124 | | - alignItems: 'center', |
125 | | - textAlign: 'center', |
| 85 | + display:'flex', |
| 86 | + flexDirection:'column', |
| 87 | + gap:8, |
| 88 | + paddingTop:24, |
| 89 | + alignItems:'center', |
| 90 | + textAlign:'center', |
| 91 | + width:'100%' |
126 | 92 | }} |
127 | 93 | > |
128 | | - {/* ACTIVITY SHOWCASE SECTION */} |
129 | | - <div> |
130 | | - <div |
131 | | - style={{ |
132 | | - border: '2px dashed #999', |
133 | | - height: '200px', |
134 | | - width: '100%', |
135 | | - maxWidth: '300px', |
136 | | - display: 'flex', |
137 | | - alignItems: 'center', |
138 | | - justifyContent: 'center', |
139 | | - margin: '0 auto', |
140 | | - }} |
141 | | - > |
142 | | - <span style={{ fontSize: '14px', color: '#999' }}>GIF Screen</span> |
143 | | - </div> |
144 | | - <p style={{ margin: '15px 0 10px 0', fontSize: '16px' }}> |
145 | | - <b>{activity}</b> |
146 | | - </p> |
| 94 | + {/* Activity clip */} |
| 95 | + <div style={{ width:'100%' }}> |
| 96 | + <img |
| 97 | + src={gifSrc} |
| 98 | + alt={activity} |
| 99 | + style={{ width:'80%', height:'auto', objectFit:'contain', display:'block', margin: '0 auto' }} |
| 100 | + /> |
| 101 | + <p style={{ margin:'15px 0 10px', fontSize:16 }}><b>{activity}</b></p> |
147 | 102 | </div> |
148 | 103 |
|
149 | | - {/* TIMER SELECTOR SECTION */} |
150 | | - <div style={{ width: '200px', margin: '0 auto' }}> |
151 | | - <div style={{ display: 'flex', alignItems: 'center', gap: '20px' }}> |
152 | | - <span style={{ fontSize: '14px' }}>Start</span> |
| 104 | + {/* Hour selector */} |
| 105 | + <div style={{ width:200, margin:'0 auto' }}> |
| 106 | + <div style={{ display:'flex', alignItems:'center', gap:20 }}> |
| 107 | + <span style={{ fontSize:14 }}>Start</span> |
153 | 108 | <FancySlider min={1} max={6} step={1} value={selectedHour} onChange={onTimeChange} /> |
154 | | - <span style={{ fontSize: '14px' }}>End</span> |
| 109 | + <span style={{ fontSize:14 }}>End</span> |
155 | 110 | </div> |
156 | 111 | </div> |
157 | 112 | </div> |
|
0 commit comments