'use client'; import { Slider } from '@/components/ui/slider'; import { MousePointerClick } from 'lucide-react'; import { cn } from '@/lib/utils/cn'; import type { Keyframe, KeyframeProperties, TransformValue } from '@/types/animate'; import { DEFAULT_TRANSFORM } from '@/lib/animate/defaults'; interface Props { keyframe: Keyframe | null; onChange: (id: string, props: KeyframeProperties) => void; } interface SliderRowProps { label: string; unit?: string; value: number; min: number; max: number; step?: number; onChange: (v: number) => void; } function SliderRow({ label, unit, value, min, max, step = 1, onChange }: SliderRowProps) { return (
onChange(v)} />
onChange(Number(e.target.value))} className="w-14 bg-transparent border border-border/40 rounded-md px-1.5 py-1 text-[10px] font-mono text-center outline-none focus:border-primary/50 transition-colors text-foreground/80 mt-4" />
); } export function KeyframeProperties({ keyframe, onChange }: Props) { if (!keyframe) { return (

Select a keyframe on the timeline to edit its properties

); } const props = keyframe.properties; const t: TransformValue = { ...DEFAULT_TRANSFORM, ...props.transform }; const setTransform = (key: keyof TransformValue, value: number) => { onChange(keyframe.id, { ...props, transform: { ...t, [key]: value } }); }; const setProp = (key: K, value: KeyframeProperties[K]) => { onChange(keyframe.id, { ...props, [key]: value }); }; const hasBg = props.backgroundColor && props.backgroundColor !== 'none'; return (
Properties {keyframe.offset}%
{/* Transform */}

Transform

setTransform('translateX', v)} /> setTransform('translateY', v)} /> setTransform('rotate', v)} /> setTransform('scaleX', v)} /> setTransform('scaleY', v)} /> setTransform('skewX', v)} /> setTransform('skewY', v)} />
{/* Visual */}

Visual

setProp('opacity', v)} /> {/* Background color */}
setProp('backgroundColor', e.target.value)} disabled={!hasBg} className={cn('w-8 h-8 rounded-lg cursor-pointer border border-border/40 bg-transparent shrink-0 p-0.5', !hasBg && 'opacity-30 cursor-not-allowed')} /> setProp('backgroundColor', e.target.value)} disabled={!hasBg} placeholder="none" className="flex-1 bg-transparent border border-border/40 rounded-lg px-3 py-1.5 text-xs font-mono outline-none focus:border-primary/50 transition-colors text-foreground/80 placeholder:text-muted-foreground/30 disabled:opacity-30" />
setProp('borderRadius', v)} />
{/* Filters */}

Filter

setProp('blur', v)} /> setProp('brightness', v)} />
); }