Skip to content

Commit 61953a7

Browse files
committed
Change speed menu to slider
1 parent 0da77ff commit 61953a7

File tree

1 file changed

+46
-41
lines changed

1 file changed

+46
-41
lines changed
Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,60 @@
11
'use client';
22

3-
import {
4-
Listbox,
5-
ListboxButton,
6-
ListboxOption,
7-
ListboxOptions,
8-
} from '@headlessui/react';
3+
import { Input, Popover, PopoverButton, PopoverPanel } from '@headlessui/react';
94
import { ChevronUpDownIcon } from '@/components/icons/Icons';
105
import { useConfig } from '@/contexts/ConfigContext';
11-
12-
const speedOptions = [
13-
{ value: 0.5, label: '0.5x' },
14-
{ value: 0.75, label: '0.75x' },
15-
{ value: 1, label: '1x' },
16-
{ value: 1.25, label: '1.25x' },
17-
{ value: 1.5, label: '1.5x' },
18-
{ value: 1.75, label: '1.75x' },
19-
{ value: 2, label: '2x' },
20-
{ value: 2.5, label: '2.5x' },
21-
{ value: 3, label: '3x' },
22-
];
6+
import { useCallback, useEffect, useState } from 'react';
237

248
export const SpeedControl = ({ setSpeedAndRestart }: {
259
setSpeedAndRestart: (speed: number) => void;
2610
}) => {
2711
const { voiceSpeed } = useConfig();
12+
const [localSpeed, setLocalSpeed] = useState(voiceSpeed);
13+
14+
// Sync local speed with global state
15+
useEffect(() => {
16+
setLocalSpeed(voiceSpeed);
17+
}, [voiceSpeed]);
18+
19+
// Handler for slider change (updates local state only)
20+
const handleSpeedChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
21+
setLocalSpeed(parseFloat(event.target.value));
22+
}, []);
2823

29-
// Use voiceSpeed as the source of truth
30-
const currentSpeed = voiceSpeed;
24+
// Handler for slider release
25+
const handleSpeedChangeComplete = useCallback(() => {
26+
if (localSpeed !== voiceSpeed) {
27+
setSpeedAndRestart(localSpeed);
28+
}
29+
}, [localSpeed, voiceSpeed, setSpeedAndRestart]);
3130

3231
return (
33-
<div className="relative">
34-
<Listbox value={currentSpeed} onChange={setSpeedAndRestart}>
35-
<ListboxButton className="flex items-center space-x-0.5 sm:space-x-1 bg-transparent text-foreground text-xs sm:text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-1.5 sm:pl-2 pr-0.5 sm:pr-1 py-0.5 sm:py-1">
36-
<span>{currentSpeed}x</span>
37-
<ChevronUpDownIcon className="h-2.5 w-2.5 sm:h-3 sm:w-3" />
38-
</ListboxButton>
39-
<ListboxOptions anchor='top start' className="absolute z-50 w-20 sm:w-24 overflow-auto rounded-lg bg-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
40-
{speedOptions.map((option) => (
41-
<ListboxOption
42-
key={option.value}
43-
value={option.value}
44-
className={({ active, selected }) =>
45-
`relative cursor-pointer select-none py-0.5 px-1.5 sm:py-2 sm:px-3 ${active ? 'bg-offbase' : ''} ${selected ? 'font-medium' : ''}`
46-
}
47-
>
48-
<span className='text-xs sm:text-sm'>{option.label}</span>
49-
</ListboxOption>
50-
))}
51-
</ListboxOptions>
52-
</Listbox>
53-
</div>
32+
<Popover className="relative">
33+
<PopoverButton className="flex items-center space-x-0.5 sm:space-x-1 bg-transparent text-foreground text-xs sm:text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-1.5 sm:pl-2 pr-0.5 sm:pr-1 py-0.5 sm:py-1">
34+
<span>{Number.isInteger(localSpeed) ? localSpeed.toString() : localSpeed.toFixed(1)}x</span>
35+
<ChevronUpDownIcon className="h-2.5 w-2.5 sm:h-3 sm:w-3" />
36+
</PopoverButton>
37+
<PopoverPanel anchor="top" className="absolute z-50 bg-base p-3 rounded-md shadow-lg border border-offbase">
38+
<div className="flex flex-col space-y-2">
39+
<div className="flex justify-between">
40+
<span className="text-xs">0.5x</span>
41+
<span className="text-xs font-bold">{Number.isInteger(localSpeed) ? localSpeed.toString() : localSpeed.toFixed(1)}x</span>
42+
<span className="text-xs">3x</span>
43+
</div>
44+
<Input
45+
type="range"
46+
min="0.5"
47+
max="3"
48+
step="0.1"
49+
value={localSpeed}
50+
onChange={handleSpeedChange}
51+
onMouseUp={handleSpeedChangeComplete}
52+
onKeyUp={handleSpeedChangeComplete}
53+
onTouchEnd={handleSpeedChangeComplete}
54+
className="w-full bg-offbase rounded-lg appearance-none cursor-pointer accent-accent [&::-webkit-slider-runnable-track]:bg-offbase [&::-webkit-slider-runnable-track]:rounded-lg [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-accent [&::-moz-range-track]:bg-offbase [&::-moz-range-track]:rounded-lg [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-accent"
55+
/>
56+
</div>
57+
</PopoverPanel>
58+
</Popover>
5459
);
5560
}

0 commit comments

Comments
 (0)