video-flow-b/components/ui/character-editor.tsx
2025-09-01 21:25:33 +08:00

96 lines
3.1 KiB
TypeScript

import React, { useState, useRef, useEffect, forwardRef } from "react";
import { motion } from "framer-motion";
import { Sparkles, X, Plus, RefreshCw, Loader2 } from 'lucide-react';
import MainEditor from "./main-editor/MainEditor";
import { cn } from "@/public/lib/utils";
import { TextToShotAdapter } from "@/app/service/adapter/textToShot";
import { TagValueObject } from "@/app/service/domain/valueObject";
interface CharacterEditorProps {
className?: string;
description: string;
highlight: TagValueObject[];
onSmartPolish: (text: string) => void;
onUpdateText: (text: string) => void;
disabled?: boolean;
}
export const CharacterEditor = forwardRef<any, CharacterEditorProps>(({
className,
description,
highlight,
onSmartPolish,
onUpdateText,
disabled
}, ref) => {
const [isOptimizing, setIsOptimizing] = useState(false);
const [content, setContent] = useState<any[]>([]);
const [isInit, setIsInit] = useState(true);
const handleSmartPolish = async () => {
setIsOptimizing(true);
console.log('-==========handleSmartPolish===========-', content);
const text = TextToShotAdapter.fromRoleToText(content);
console.log('-==========getText===========-', text);
onSmartPolish(text);
};
const handleChangeContent = (content: any) => {
console.log('-==========handleChangeContent===========-', content);
onUpdateText(TextToShotAdapter.fromRoleToText(content));
setContent(content);
};
useEffect(() => {
setIsInit(true);
console.log('-==========description===========-', description);
console.log('-==========highlight===========-', highlight);
const paragraphs = TextToShotAdapter.fromTextToRole(description, highlight);
console.log('-==========paragraphs===========-', paragraphs);
setContent(paragraphs);
// 保存定时器ID
const timerId = setTimeout(() => {
setIsInit(false);
setIsOptimizing(false);
}, 100);
// 清理函数:组件卸载时清理定时器
return () => {
clearTimeout(timerId);
};
}, [description]);
// 暴露方法给父组件
React.useImperativeHandle(ref, () => ({
getRoleText: () => {
return TextToShotAdapter.fromRoleToText(content);
}
}));
return (
<div className={cn("space-y-2 border border-white/10 relative p-2 rounded-[0.5rem] pb-12", className)}>
{/* 自由输入区域 */}
{
!isInit && <MainEditor content={content} onChangeContent={handleChangeContent} disabled={disabled} />
}
{/* 智能润色按钮 */}
<motion.button
onClick={handleSmartPolish}
disabled={isOptimizing}
className="absolute bottom-3 right-3 flex items-center gap-1.5 px-3 py-1.5
bg-purple-500/10 hover:bg-purple-500/20 text-purple-500 rounded-full
transition-colors text-xs disabled:opacity-50"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
{isOptimizing ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Sparkles className="w-3.5 h-3.5" />}
<span>{isOptimizing ? "Optimizing..." : "Optimization"}</span>
</motion.button>
</div>
);
});
CharacterEditor.displayName = 'CharacterEditor';