Skip to content

Commit 876ceb9

Browse files
feat: allow custom time control via sliders
1 parent e9ae508 commit 876ceb9

File tree

1 file changed

+118
-13
lines changed

1 file changed

+118
-13
lines changed

src/components/Common/PlaySetupModal.tsx

Lines changed: 118 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
8282
const [timeControl, setTimeControl] = useState<TimeControl>(
8383
props.timeControl || TimeControlOptions[0],
8484
)
85+
const [timeMinutes, setTimeMinutes] = useState<number>(() => {
86+
const initial = props.timeControl || TimeControlOptions[0]
87+
if (initial === 'unlimited') return 0
88+
return parseInt(initial.split('+')[0])
89+
})
90+
const [incrementSeconds, setIncrementSeconds] = useState<number>(() => {
91+
const initial = props.timeControl || TimeControlOptions[0]
92+
if (initial === 'unlimited') return 0
93+
return parseInt(initial.split('+')[1])
94+
})
8595
const [isBrain, setIsBrain] = useState<boolean>(props.isBrain || false)
8696
const [sampleMoves, setSampleMoves] = useState<boolean>(
8797
props.sampleMoves || true,
@@ -102,6 +112,38 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
102112

103113
const [openMoreOptions, setMoreOptionsOpen] = useState<boolean>(true)
104114

115+
const handlePresetSelect = useCallback((preset: TimeControl) => {
116+
setTimeControl(preset)
117+
if (preset === 'unlimited') {
118+
setTimeMinutes(0)
119+
setIncrementSeconds(0)
120+
} else {
121+
const [minutes, increment] = preset.split('+').map(Number)
122+
setTimeMinutes(minutes)
123+
setIncrementSeconds(increment)
124+
}
125+
}, [])
126+
127+
const handleSliderChange = useCallback(
128+
(newTimeMinutes: number, newIncrementSeconds: number) => {
129+
setTimeMinutes(newTimeMinutes)
130+
setIncrementSeconds(newIncrementSeconds)
131+
132+
if (newTimeMinutes === 0 && newIncrementSeconds === 0) {
133+
setTimeControl('unlimited')
134+
} else {
135+
const newTimeControl =
136+
`${newTimeMinutes}+${newIncrementSeconds}` as TimeControl
137+
if (TimeControlOptions.includes(newTimeControl)) {
138+
setTimeControl(newTimeControl)
139+
} else {
140+
setTimeControl(newTimeControl)
141+
}
142+
}
143+
},
144+
[],
145+
)
146+
105147
const start = useCallback(
106148
(color: Color | undefined) => {
107149
const player = color ?? ['white', 'black'][Math.floor(Math.random() * 2)]
@@ -248,19 +290,82 @@ export const PlaySetupModal: React.FC<Props> = (props: Props) => {
248290
</div>
249291

250292
<div>
251-
<label
252-
htmlFor="time-control-select"
253-
className="mb-1 block text-sm font-medium text-primary"
254-
>
255-
Time control:
256-
</label>
257-
<div id="time-control-select">
258-
<OptionSelect
259-
options={TimeControlOptions}
260-
labels={TimeControlOptionNames}
261-
selected={timeControl}
262-
onChange={setTimeControl}
263-
/>
293+
<div className="mb-3 flex items-center justify-between">
294+
<span className="text-sm font-medium text-primary">
295+
Time Control:
296+
</span>
297+
<div className="flex gap-1">
298+
{TimeControlOptions.map((option, index) => (
299+
<button
300+
key={option}
301+
onClick={() => handlePresetSelect(option)}
302+
className={`rounded px-2 py-1 text-xs font-medium transition-colors ${
303+
timeControl === option
304+
? 'bg-human-4 text-white'
305+
: 'bg-background-2 text-secondary hover:bg-background-3 hover:text-primary'
306+
}`}
307+
>
308+
{TimeControlOptionNames[index]}
309+
</button>
310+
))}
311+
</div>
312+
</div>
313+
314+
<div className="space-y-3">
315+
<div>
316+
<div className="mb-2 flex items-center justify-between">
317+
<label
318+
htmlFor="time-minutes-slider"
319+
className="text-xs font-medium text-primary"
320+
>
321+
Time (minutes)
322+
</label>
323+
<span className="text-xs text-secondary">
324+
{timeMinutes}
325+
</span>
326+
</div>
327+
<input
328+
id="time-minutes-slider"
329+
type="range"
330+
min="0"
331+
max="60"
332+
step="1"
333+
value={timeMinutes}
334+
onChange={(e) =>
335+
handleSliderChange(
336+
Number(e.target.value),
337+
incrementSeconds,
338+
)
339+
}
340+
className="h-2 w-full cursor-pointer appearance-none rounded-lg bg-background-2 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-human-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-human-4"
341+
/>
342+
</div>
343+
344+
<div>
345+
<div className="mb-2 flex items-center justify-between">
346+
<label
347+
htmlFor="increment-seconds-slider"
348+
className="text-xs font-medium text-primary"
349+
>
350+
Increment (seconds)
351+
</label>
352+
<span className="text-xs text-secondary">
353+
{incrementSeconds}
354+
</span>
355+
</div>
356+
<input
357+
id="increment-seconds-slider"
358+
type="range"
359+
min="0"
360+
max="30"
361+
step="1"
362+
value={incrementSeconds}
363+
onChange={(e) =>
364+
handleSliderChange(timeMinutes, Number(e.target.value))
365+
}
366+
className="h-2 w-full cursor-pointer appearance-none rounded-lg bg-background-2 [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-human-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-human-4"
367+
/>
368+
</div>
264369
</div>
265370
</div>
266371

0 commit comments

Comments
 (0)