nicolium: add slight slider animation

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-02-21 15:35:34 +01:00
parent f34dae6a18
commit dafec66d90
2 changed files with 46 additions and 4 deletions

View File

@ -1,5 +1,6 @@
import clsx from 'clsx';
import throttle from 'lodash/throttle';
import React, { useCallback, useRef } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { getPointerPosition } from '@/features/video';
@ -13,8 +14,34 @@ interface ISlider {
/** Draggable slider component. */
const Slider: React.FC<ISlider> = ({ value, onChange }) => {
const node = useRef<HTMLDivElement>(null);
const keyboardAnimationTimeout = useRef<number | null>(null);
const [animateKeyboardInput, setAnimateKeyboardInput] = useState<boolean>(false);
const clearKeyboardAnimation = useCallback(() => {
if (keyboardAnimationTimeout.current !== null) {
window.clearTimeout(keyboardAnimationTimeout.current);
keyboardAnimationTimeout.current = null;
}
setAnimateKeyboardInput(false);
}, []);
const triggerKeyboardAnimation = useCallback(() => {
setAnimateKeyboardInput(true);
if (keyboardAnimationTimeout.current !== null) {
window.clearTimeout(keyboardAnimationTimeout.current);
}
keyboardAnimationTimeout.current = window.setTimeout(() => {
setAnimateKeyboardInput(false);
keyboardAnimationTimeout.current = null;
}, 120);
}, []);
const handleMouseDown: React.MouseEventHandler = (e) => {
clearKeyboardAnimation();
document.addEventListener('mousemove', handleMouseSlide, true);
document.addEventListener('mouseup', handleMouseUp, true);
document.addEventListener('touchmove', handleMouseSlide, true);
@ -86,10 +113,19 @@ const Slider: React.FC<ISlider> = ({ value, onChange }) => {
nextValue = 1;
}
triggerKeyboardAnimation();
onChange(nextValue);
}
};
useEffect(() => {
return () => {
if (keyboardAnimationTimeout.current !== null) {
window.clearTimeout(keyboardAnimationTimeout.current);
}
};
}, []);
return (
<div
className='relative inline-flex h-6 cursor-pointer transition'
@ -98,11 +134,17 @@ const Slider: React.FC<ISlider> = ({ value, onChange }) => {
>
<div className='absolute top-1/2 h-1 w-full -translate-y-1/2 rounded-full bg-primary-200 dark:bg-primary-700' />
<div
className='absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-accent-500'
className={clsx(
'absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-accent-500 transition-[width] ease-in-out',
animateKeyboardInput ? 'duration-150' : 'duration-0',
)}
style={{ width: `${value * 100}%` }}
/>
<span
className='absolute top-1/2 z-10 -ml-1.5 size-3 -translate-y-1/2 rounded-full bg-accent-500 shadow'
className={clsx(
'absolute top-1/2 z-10 -ml-1.5 size-3 -translate-y-1/2 rounded-full bg-accent-500 shadow transition-[left] ease-in-out',
animateKeyboardInput ? 'duration-150' : 'duration-0',
)}
tabIndex={0}
style={{ left: `${value * 100}%` }}
role='slider'

View File

@ -112,7 +112,7 @@ const StepSlider: React.FC<IStepSlider> = ({ value, steps, onChange }) => {
/>
))}
<span
className='absolute top-1/2 z-10 -ml-1.5 size-3 -translate-y-1/2 rounded-full bg-accent-500 shadow'
className='absolute top-1/2 z-10 -ml-1.5 size-3 -translate-y-1/2 rounded-full bg-accent-500 shadow transition-[left] duration-100 ease-in-out'
tabIndex={0}
role='slider'
aria-valuemin={0}