import { RotateCcw, Save } from "lucide-react" import { useCallback, useEffect, useState } from "react" import { useTranslation } from "react-i18next" import { Button } from "@/components/ui/button" import { Label } from "@/components/ui/label" import { Slider } from "@/components/ui/slider" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { BaseEffect, EffectParameter } from "@/features/effects/types" interface EffectParameterControlsProps { effect: BaseEffect onParametersChange: (params: Record) => void selectedPreset?: string onSavePreset?: (name: string, params: Record) => void } // Получаем конфигурацию из параметров эффекта function getParameterConfig(param: EffectParameter): { min: number max: number step: number default: any label: { ru: string; en: string } description: { ru: string; en: string } } { const label = { ru: param.name.ru || param.name.en, en: param.name.en, } const description = { ru: "", en: "", } switch (param.type) { case "number": return { min: param.min ?? 0, max: param.max ?? 100, step: param.step ?? 1, default: param.defaultValue, label, description, } case "boolean": return { min: 0, max: 1, step: 1, default: param.defaultValue ? 1 : 0, label, description, } case "dropdown": // Для dropdown используем индексы опций const options = param.options || [] const defaultIndex = options.findIndex((opt) => opt.value === param.defaultValue) return { min: 0, max: Math.max(0, options.length - 1), step: 1, default: defaultIndex >= 0 ? defaultIndex : 0, label, description, } case "color": // Для цвета будем использовать другой компонент return { min: 0, max: 255, step: 1, default: 0, label, description, } default: return { min: 0, max: 100, step: 1, default: param.defaultValue, label, description, } } } // Старая конфигурация для обратной совместимости const LEGACY_PARAMETER_CONFIG = { intensity: { min: 0, max: 100, step: 1, default: 50, label: { ru: "Интенсивность", en: "Intensity" }, description: { ru: "Сила применения эффекта", en: "Effect strength" }, }, speed: { min: 0.1, max: 5.0, step: 0.1, default: 1.0, label: { ru: "Скорость", en: "Speed" }, description: { ru: "Скорость воспроизведения", en: "Playback speed" }, }, angle: { min: 0, max: 360, step: 1, default: 0, label: { ru: "Угол", en: "Angle" }, description: { ru: "Угол поворота в градусах", en: "Rotation angle in degrees", }, }, radius: { min: 0, max: 50, step: 0.5, default: 5, label: { ru: "Радиус", en: "Radius" }, description: { ru: "Радиус размытия или эффекта", en: "Blur or effect radius", }, }, amount: { min: 0, max: 200, step: 1, default: 100, label: { ru: "Количество", en: "Amount" }, description: { ru: "Количество эффекта", en: "Effect amount" }, }, threshold: { min: 0, max: 100, step: 1, default: 50, label: { ru: "Порог", en: "Threshold" }, description: { ru: "Пороговое значение", en: "Threshold value" }, }, temperature: { min: -100, max: 100, step: 1, default: 0, label: { ru: "Температура", en: "Temperature" }, description: { ru: "Цветовая температура", en: "Color temperature" }, }, tint: { min: -100, max: 100, step: 1, default: 0, label: { ru: "Оттенок", en: "Tint" }, description: { ru: "Цветовой оттенок", en: "Color tint" }, }, } as const /** * Компонент для интерактивной настройки параметров эффекта */ export function EffectParameterControls({ effect, onParametersChange, selectedPreset, onSavePreset, }: EffectParameterControlsProps) { const { i18n, t } = useTranslation() const currentLang = i18n.language as "ru" | "en" // Состояние параметров const [parameters, setParameters] = useState>(() => { // Инициализируем значениями по умолчанию из эффекта const defaultParams: Record = {} effect.parameters?.forEach((param) => { defaultParams[param.id] = param.defaultValue }) return defaultParams }) // Обновляем параметры при смене пресета useEffect(() => { if (selectedPreset && effect.presets) { const preset = effect.presets.find((p) => p.id === selectedPreset) if (preset) { setParameters(preset.parameters) onParametersChange(preset.parameters) } } }, [selectedPreset, effect.presets, onParametersChange]) // Обработчик изменения параметра const handleParameterChange = useCallback( (paramName: string, value: number[]) => { const newValue = value[0] const newParameters = { ...parameters, [paramName]: newValue } setParameters(newParameters) onParametersChange(newParameters) }, [parameters, onParametersChange], ) // Сброс к значениям по умолчанию const handleReset = useCallback(() => { const defaultParams: Record = {} effect.parameters?.forEach((param) => { defaultParams[param.id] = param.defaultValue }) setParameters(defaultParams) onParametersChange(defaultParams) }, [effect.parameters, onParametersChange]) // Сохранение пользовательского пресета const handleSavePreset = useCallback(() => { if (onSavePreset) { // Запрашиваем имя пресета у пользователя const presetName = prompt(t("effects.enterPresetName", "Введите название пресета:")) if (presetName && presetName.trim()) { onSavePreset(presetName.trim(), parameters) } } }, [onSavePreset, parameters, t]) // Если у эффекта нет параметров, не показываем контролы if (!effect.parameters || effect.parameters.length === 0) { return null } return (
{/* Заголовок с кнопками действий */}

{t("effects.detail.parameters", "Параметры")}

{t("effects.detail.resetToDefault", "Сбросить к значениям по умолчанию")} {onSavePreset && ( {t("effects.detail.savePreset", "Сохранить как пресет")} )}
{/* Контролы параметров */}
{effect.parameters.map((param) => { const config = getParameterConfig(param) const currentValue = parameters[param.id] ?? param.defaultValue // Для цветов и сложных типов нужны специальные контролы if (param.type === "color") { // TODO: Добавить color picker return null } if (param.type === "dropdown") { // TODO: Добавить dropdown компонент с Select return null } // Преобразуем boolean в число для slider const sliderValue = param.type === "boolean" ? (currentValue ? 1 : 0) : currentValue return (
{param.type === "boolean" ? currentValue ? "Вкл" : "Выкл" : (param.type as string) === "dropdown" && param.options ? param.options[currentValue]?.label[currentLang] || param.options[currentValue]?.label.en || currentValue : currentValue}
{ const newValue = param.type === "boolean" ? value[0] === 1 : value[0] handleParameterChange( param.id, typeof newValue === "boolean" ? [newValue ? 1 : 0] : [newValue], ) }} min={config.min} max={config.max} step={config.step} className="w-full" />
{config.label[currentLang] || config.label.en}
{config.description[currentLang] || config.description.en}
{config.min} - {config.max}
) })}
{/* Информация о текущих параметрах */}
{t("effects.detail.currentValues", "Текущие значения")}:
{Object.entries(parameters).map(([key, value]) => (
{key}: {typeof value === "boolean" ? (value ? "true" : "false") : value}
))}
) }