refactor: merge keyframes/export/presets into one tabbed card
Right column now has two elements: preview canvas (shrink-0) and a single glass card with Keyframes|Export|Presets tabs (flex-1). Defaults to Keyframes tab. Removes the standalone timeline card and the redundant embedded timeline in the mobile edit panel. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ import { cn } from '@/lib/utils/cn';
|
|||||||
import type { AnimationConfig, KeyframeProperties as KFProps, PreviewElement } from '@/types/animate';
|
import type { AnimationConfig, KeyframeProperties as KFProps, PreviewElement } from '@/types/animate';
|
||||||
|
|
||||||
type MobileTab = 'edit' | 'preview';
|
type MobileTab = 'edit' | 'preview';
|
||||||
type RightTab = 'export' | 'presets';
|
type RightTab = 'keyframes' | 'export' | 'presets';
|
||||||
|
|
||||||
export function AnimationEditor() {
|
export function AnimationEditor() {
|
||||||
const [config, setConfig] = useState<AnimationConfig>(DEFAULT_CONFIG);
|
const [config, setConfig] = useState<AnimationConfig>(DEFAULT_CONFIG);
|
||||||
@@ -21,7 +21,7 @@ export function AnimationEditor() {
|
|||||||
);
|
);
|
||||||
const [previewElement, setPreviewElement] = useState<PreviewElement>('box');
|
const [previewElement, setPreviewElement] = useState<PreviewElement>('box');
|
||||||
const [mobileTab, setMobileTab] = useState<MobileTab>('edit');
|
const [mobileTab, setMobileTab] = useState<MobileTab>('edit');
|
||||||
const [rightTab, setRightTab] = useState<RightTab>('export');
|
const [rightTab, setRightTab] = useState<RightTab>('keyframes');
|
||||||
|
|
||||||
const selectedKeyframe = config.keyframes.find((k) => k.id === selectedId) ?? null;
|
const selectedKeyframe = config.keyframes.find((k) => k.id === selectedId) ?? null;
|
||||||
|
|
||||||
@@ -108,33 +108,22 @@ export function AnimationEditor() {
|
|||||||
|
|
||||||
<div className="border-t border-border/25" />
|
<div className="border-t border-border/25" />
|
||||||
|
|
||||||
{/* Timeline — embedded inside edit panel on mobile, hidden on desktop */}
|
|
||||||
<div className="lg:hidden">
|
|
||||||
<KeyframeTimeline {...timelineProps} embedded />
|
|
||||||
</div>
|
|
||||||
<div className="lg:hidden border-t border-border/25" />
|
|
||||||
|
|
||||||
<KeyframeProperties keyframe={selectedKeyframe} onChange={updateKeyframeProps} />
|
<KeyframeProperties keyframe={selectedKeyframe} onChange={updateKeyframeProps} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right: Preview + Timeline + Export/Presets */}
|
{/* Right: Preview + tabbed panel */}
|
||||||
<div className={cn('lg:col-span-3 flex flex-col gap-3 overflow-hidden', mobileTab !== 'preview' && 'hidden lg:flex')}>
|
<div className={cn('lg:col-span-3 flex flex-col gap-3 overflow-hidden', mobileTab !== 'preview' && 'hidden lg:flex')}>
|
||||||
|
|
||||||
{/* Preview canvas */}
|
{/* Preview canvas */}
|
||||||
<AnimationPreview config={config} element={previewElement} onElementChange={setPreviewElement} />
|
<AnimationPreview config={config} element={previewElement} onElementChange={setPreviewElement} />
|
||||||
|
|
||||||
{/* Timeline — standalone on desktop */}
|
{/* Keyframes / Export / Presets tab panel */}
|
||||||
<div className="hidden lg:block shrink-0">
|
|
||||||
<KeyframeTimeline {...timelineProps} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Export / Presets tab panel */}
|
|
||||||
<div className="glass rounded-xl p-4 flex flex-col flex-1 min-h-0 overflow-hidden">
|
<div className="glass rounded-xl p-4 flex flex-col flex-1 min-h-0 overflow-hidden">
|
||||||
{/* Tab switcher */}
|
{/* Tab switcher */}
|
||||||
<div className="flex glass rounded-lg p-0.5 gap-0.5 mb-4 shrink-0">
|
<div className="flex glass rounded-lg p-0.5 gap-0.5 mb-4 shrink-0">
|
||||||
{(['export', 'presets'] as RightTab[]).map((t) => (
|
{(['keyframes', 'export', 'presets'] as RightTab[]).map((t) => (
|
||||||
<button
|
<button
|
||||||
key={t}
|
key={t}
|
||||||
onClick={() => setRightTab(t)}
|
onClick={() => setRightTab(t)}
|
||||||
@@ -145,12 +134,13 @@ export function AnimationEditor() {
|
|||||||
: 'text-muted-foreground hover:text-foreground'
|
: 'text-muted-foreground hover:text-foreground'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{t === 'export' ? 'Export' : 'Presets'}
|
{t === 'keyframes' ? 'Keyframes' : t === 'export' ? 'Export' : 'Presets'}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div className="flex-1 min-h-0 overflow-y-auto scrollbar-thin scrollbar-thumb-primary/20 scrollbar-track-transparent pr-0.5">
|
<div className="flex-1 min-h-0 overflow-y-auto scrollbar-thin scrollbar-thumb-primary/20 scrollbar-track-transparent pr-0.5">
|
||||||
|
{rightTab === 'keyframes' && <KeyframeTimeline {...timelineProps} embedded />}
|
||||||
{rightTab === 'export' && <ExportPanel config={config} />}
|
{rightTab === 'export' && <ExportPanel config={config} />}
|
||||||
{rightTab === 'presets' && <PresetLibrary onSelect={loadPreset} />}
|
{rightTab === 'presets' && <PresetLibrary onSelect={loadPreset} />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user