import { useCallback, useState } from "react" import { cn } from "@/lib/utils" interface ParameterSliderProps { label: string value: number onChange: (value: number) => void min: number max: number step?: number defaultValue?: number disabled?: boolean className?: string showValue?: boolean formatValue?: (value: number) => string } export function ParameterSlider({ label, value, onChange, min, max, step = 1, defaultValue, disabled = false, className, showValue = true, formatValue = (v) => v.toString(), }: ParameterSliderProps) { const [isDragging, setIsDragging] = useState(false) // Вычисляем процент для позиции слайдера const percentage = ((value - min) / (max - min)) * 100 // Определяем цвет слайдера в зависимости от значения const getSliderColor = useCallback(() => { if (defaultValue !== undefined) { if (value === defaultValue) return "bg-gray-500" if (value > defaultValue) return "bg-blue-500" return "bg-orange-500" } return "bg-blue-500" }, [value, defaultValue]) const handleChange = useCallback( (e: React.ChangeEvent) => { onChange(Number(e.target.value)) }, [onChange], ) const handleDoubleClick = useCallback(() => { if (defaultValue !== undefined && !disabled) { onChange(defaultValue) } }, [defaultValue, disabled, onChange]) return (
{showValue && {formatValue(value)}}
{/* Фоновый трек */}
{/* Заполненная часть */}
{/* Центральная метка (если есть defaultValue) */} {defaultValue !== undefined && (
)} {/* Невидимый input range для взаимодействия */} setIsDragging(true)} onMouseUp={() => setIsDragging(false)} disabled={disabled} className={cn( "relative w-full h-2 appearance-none bg-transparent cursor-pointer", "focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 rounded-lg", "[&::-webkit-slider-thumb]:appearance-none", "[&::-webkit-slider-thumb]:w-4", "[&::-webkit-slider-thumb]:h-4", "[&::-webkit-slider-thumb]:bg-white", "[&::-webkit-slider-thumb]:rounded-full", "[&::-webkit-slider-thumb]:shadow-md", "[&::-webkit-slider-thumb]:cursor-pointer", "[&::-webkit-slider-thumb]:transition-transform", "[&::-webkit-slider-thumb]:hover:scale-110", "[&::-moz-range-thumb]:appearance-none", "[&::-moz-range-thumb]:w-4", "[&::-moz-range-thumb]:h-4", "[&::-moz-range-thumb]:bg-white", "[&::-moz-range-thumb]:rounded-full", "[&::-moz-range-thumb]:shadow-md", "[&::-moz-range-thumb]:cursor-pointer", "[&::-moz-range-thumb]:transition-transform", "[&::-moz-range-thumb]:hover:scale-110", "[&::-moz-range-thumb]:border-0", disabled && "opacity-50 cursor-not-allowed", )} /> {/* Подсказка при наведении */} {!disabled && defaultValue !== undefined && (
Double-click to reset
)}
) }