'use client'; import { Infinity } from 'lucide-react'; import { cn } from '@/lib/utils/cn'; import type { AnimationConfig } from '@/types/animate'; interface Props { config: AnimationConfig; onChange: (config: AnimationConfig) => void; } const EASINGS = [ { value: 'linear', label: 'Linear' }, { value: 'ease', label: 'Ease' }, { value: 'ease-in', label: 'Ease In' }, { value: 'ease-out', label: 'Ease Out' }, { value: 'ease-in-out', label: 'Ease In Out' }, { value: 'cubic-bezier', label: 'Cubic Bézier' }, { value: 'steps(4, end)', label: 'Steps (4)' }, { value: 'steps(8, end)', label: 'Steps (8)' }, ]; const DIRECTIONS: { value: AnimationConfig['direction']; label: string }[] = [ { value: 'normal', label: 'Normal' }, { value: 'reverse', label: 'Reverse' }, { value: 'alternate', label: 'Alt' }, { value: 'alternate-reverse', label: 'Alt-Rev' }, ]; const FILL_MODES: { value: AnimationConfig['fillMode']; label: string }[] = [ { value: 'none', label: 'None' }, { value: 'forwards', label: 'Fwd' }, { value: 'backwards', label: 'Bwd' }, { value: 'both', label: 'Both' }, ]; const inputCls = 'w-full bg-transparent border border-border/40 rounded-lg px-3 py-2 text-xs font-mono outline-none focus:border-primary/50 transition-colors text-foreground/80 placeholder:text-muted-foreground/30'; const pillCls = (active: boolean) => cn( 'flex-1 py-1.5 rounded-lg border text-[10px] font-mono transition-all', active ? 'bg-primary/10 border-primary/40 text-primary' : 'border-border/30 text-muted-foreground hover:border-primary/30 hover:text-foreground' ); export function AnimationSettings({ config, onChange }: Props) { const set = (key: K, value: AnimationConfig[K]) => onChange({ ...config, [key]: value }); const isInfinite = config.iterationCount === 'infinite'; const isCubic = config.easing.startsWith('cubic-bezier'); const cubicValues = (() => { const m = config.easing.match(/cubic-bezier\(([^)]+)\)/); if (!m) return [0.25, 0.1, 0.25, 1.0]; return m[1].split(',').map(Number); })(); const setCubic = (index: number, val: number) => { const v = [...cubicValues]; v[index] = val; set('easing', `cubic-bezier(${v.join(',')})`); }; const easingSelectValue = isCubic ? 'cubic-bezier' : config.easing; return (
Settings {/* Name */}
{ const val = e.target.value.replace(/\s+/g, '-').replace(/[^a-zA-Z0-9-_]/g, ''); set('name', val || 'myAnimation'); }} className={inputCls} />
{/* Duration + Delay */}
set('duration', Math.max(50, Number(e.target.value)))} className={inputCls} />
set('delay', Math.max(0, Number(e.target.value)))} className={inputCls} />
{/* Easing */}
{/* Cubic-bezier inputs */} {isCubic && (
{(['P1x', 'P1y', 'P2x', 'P2y'] as const).map((label, i) => (
setCubic(i, Number(e.target.value))} className="w-full bg-transparent border border-border/40 rounded-lg px-2 py-1.5 text-[10px] font-mono outline-none focus:border-primary/50 transition-colors text-foreground/80 text-center" />
))}
)} {/* Iterations */}
set('iterationCount', Math.max(1, Number(e.target.value)))} placeholder="1" className={cn(inputCls, 'flex-1', isInfinite && 'opacity-30')} />
{/* Direction */}
{DIRECTIONS.map(({ value, label }) => ( ))}
{/* Fill Mode */}
{FILL_MODES.map(({ value, label }) => ( ))}
); }