import type { ComponentType, CSSProperties, ReactNode } from 'react'; import { RefreshCcw } from 'lucide-react'; import { type AnimationState, type Character, } from '../../types'; import { CORE_ACTIONS } from './roleAssetStudioModel'; type ActionButtonProps = { icon?: ReactNode; label: string; subLabel?: string; onClick: () => void; disabled?: boolean; tone?: 'default' | 'sky' | 'green'; }; type FieldProps = { label: string; children: ReactNode; }; type SectionProps = { title: string; children: ReactNode; }; type StatusBadgeProps = { tone: 'green' | 'amber' | 'zinc'; children: ReactNode; }; type TextAreaProps = { value: string; onChange: (value: string) => void; rows?: number; placeholder?: string; readOnly?: boolean; }; type CharacterAnimatorProps = { state: AnimationState; character: Character; className?: string; style?: CSSProperties; imageClassName?: string; playbackRate?: number; }; export function RpgCreationRoleAnimationSection(props: { ActionButton: (props: ActionButtonProps) => ReactNode; CharacterAnimator: ComponentType; Field: (props: FieldProps) => ReactNode; Section: (props: SectionProps) => ReactNode; StatusBadge: (props: StatusBadgeProps) => ReactNode; TextArea: (props: TextAreaProps) => ReactNode; animationPreviewFrameStyle: CSSProperties; animationPreviewPlaybackRate: number; animationPreviewViewportStyle: CSSProperties; animationPromptText: string; generatingAnimationMap: Partial>; hasGeneratedAnimation: (animation: AnimationState) => boolean; isSelectedAnimationGenerating: boolean; previewCharacter: Character | null; previewImageSrc: string; selectedAnimation: AnimationState; selectedAnimationStatus: string | null; shouldUseSelectedAnimationPreview: boolean; syncBusy: boolean; animationPointCost: number; workingRoleImageSrc?: string; workingRoleGeneratedVisualAssetId?: string; workingRoleName: string; onAnimationPromptChange: (value: string) => void; onGenerateAnimation: () => void; onPlaybackRateChange: (value: number) => void; onSelectAnimation: (animation: AnimationState) => void; }) { const { ActionButton, CharacterAnimator, Field, Section, StatusBadge, TextArea, animationPreviewFrameStyle, animationPreviewPlaybackRate, animationPreviewViewportStyle, animationPromptText, generatingAnimationMap, hasGeneratedAnimation, isSelectedAnimationGenerating, previewCharacter, previewImageSrc, selectedAnimation, selectedAnimationStatus, shouldUseSelectedAnimationPreview, syncBusy, animationPointCost, workingRoleGeneratedVisualAssetId, workingRoleImageSrc, workingRoleName, onAnimationPromptChange, onGenerateAnimation, onPlaybackRateChange, onSelectAnimation, } = props; return (
{shouldUseSelectedAnimationPreview && previewCharacter ? (
) : previewImageSrc ? ( {workingRoleName} ) : (
暂无动作预览
)}
onPlaybackRateChange(Number.parseFloat(event.target.value) || 0.75) } className="w-full accent-sky-400" />
0.25x {animationPreviewPlaybackRate.toFixed(2)}x 1.50x
{CORE_ACTIONS.map((item) => { const isSelected = item.animation === selectedAnimation; const isReady = hasGeneratedAnimation(item.animation); const isGenerating = generatingAnimationMap[item.animation] === true; return ( ); })}