'use client'; import { useEffect, useRef, useState } from 'react'; import { Play, Pause, RotateCcw, Square, Circle, Type } from 'lucide-react'; import { cn, iconBtn } from '@/lib/utils'; import { buildCSS } from '@/lib/animate/cssBuilder'; import type { AnimationConfig, PreviewElement } from '@/types/animate'; interface Props { config: AnimationConfig; element: PreviewElement; onElementChange: (e: PreviewElement) => void; } type AnimState = 'playing' | 'paused' | 'ended'; const SPEEDS: { label: string; value: string }[] = [ { label: '0.25×', value: '0.25' }, { label: '0.5×', value: '0.5' }, { label: '1×', value: '1' }, { label: '2×', value: '2' }, ]; const ELEMENTS: { value: PreviewElement; icon: React.ReactNode; title: string }[] = [ { value: 'box', icon: , title: 'Box' }, { value: 'circle', icon: , title: 'Circle' }, { value: 'text', icon: , title: 'Text' }, ]; const previewBtn = cn(iconBtn, 'w-7 h-7'); const pillCls = (active: boolean) => cn( 'px-2 py-0.5 rounded text-[10px] font-mono transition-all', active ? 'text-primary bg-primary/10' : 'text-muted-foreground/50 hover:text-muted-foreground' ); export function AnimationPreview({ config, element, onElementChange }: Props) { const styleRef = useRef(null); const [restartKey, setRestartKey] = useState(0); const [animState, setAnimState] = useState('playing'); const [speed, setSpeed] = useState('1'); useEffect(() => { if (!styleRef.current) { styleRef.current = document.createElement('style'); styleRef.current.id = 'kit-animate-preview'; document.head.appendChild(styleRef.current); } styleRef.current.textContent = buildCSS(config); setAnimState('playing'); setRestartKey((k) => k + 1); }, [config]); useEffect(() => { return () => { styleRef.current?.remove(); }; }, []); const restart = () => { setAnimState('playing'); setRestartKey((k) => k + 1); }; const scaledDuration = Math.round(config.duration / Number(speed)); const isInfinite = config.iterationCount === 'infinite'; return (
{/* Header: speed pills */}
Preview
{SPEEDS.map((s) => ( ))}
{/* Canvas */}
!isInfinite && setAnimState('ended')} > {element === 'box' && (
)} {element === 'circle' && (
)} {element === 'text' && ( Hello )}
{/* Controls: element selector + playback */}
{/* Element picker */}
{ELEMENTS.map(({ value, icon, title }) => ( ))}
{/* Playback */}
); }