@@ -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