220 lines
8.9 KiB
TypeScript

import React from 'react';
import { Camera } from 'lucide-react';
import { TypewriterText } from './common/TypewriterText';
import { ContentCard } from './common/ContentCard';
import { SkeletonCard } from './common/SkeletonCard';
import { IconLoading } from './common/IconLoading';
interface StoryboardContent {
shotLanguage?: Array<{
id: string;
stableId: string;
type: string;
purpose: string;
usage: string;
}>;
composition?: {
stableId: string;
principles: string;
aesthetics: string;
framing: string;
};
cameraMovement?: Array<{
id: string;
stableId: string;
type: string;
purpose: string;
application: string;
}>;
visualNarrative?: {
stableId: string;
logic: string;
progression: string;
emphasis: string;
};
editingPoints?: Array<{
id: string;
stableId: string;
moment: string;
cut: string;
}>;
}
interface StoryboardArtistProps {
currentContent: StoryboardContent;
isPlaying: boolean;
}
const StoryboardArtist: React.FC<StoryboardArtistProps> = ({ currentContent, isPlaying }) => {
return (
<div className="grid grid-cols-2 gap-4 h-full">
{/* 左侧:镜头语言和构图美学 */}
<div className="space-y-4 overflow-y-auto">
{/* 镜头语言选择 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Camera} isActive={!currentContent.shotLanguage && isPlaying} color="#06b6d4" />
</h3>
<div className="space-y-3">
{currentContent.shotLanguage && currentContent.shotLanguage.length > 0 ? (
currentContent.shotLanguage.map((shot) => (
<ContentCard
key={shot.stableId}
className="bg-cyan-500/20 rounded-lg p-3 border border-cyan-500/30"
>
<div className="flex justify-between items-center mb-2">
<span className="text-cyan-300 font-medium text-sm">{shot.type}</span>
<span className="text-gray-400 text-xs">{shot.purpose}</span>
</div>
<div className="text-gray-300 text-xs leading-relaxed">
<TypewriterText text={shot.usage} stableId={shot.stableId} />
</div>
</ContentCard>
))
) : (
Array.from({length: 4}, (_, i) => (
<SkeletonCard key={i} className="bg-cyan-500/20 rounded-lg p-3 border border-cyan-500/30" />
))
)}
</div>
</div>
{/* 构图美学运用 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Camera} isActive={!currentContent.composition && isPlaying} color="#06b6d4" />
</h3>
{currentContent.composition ? (
<ContentCard className="space-y-3">
<div>
<div className="text-cyan-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.composition.principles} stableId={`${currentContent.composition.stableId}-principles`} />
</div>
</div>
<div>
<div className="text-cyan-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.composition.aesthetics} stableId={`${currentContent.composition.stableId}-aesthetics`} />
</div>
</div>
<div>
<div className="text-cyan-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.composition.framing} stableId={`${currentContent.composition.stableId}-framing`} />
</div>
</div>
</ContentCard>
) : (
<div className="space-y-3">
{Array.from({length: 3}, (_, i) => (
<SkeletonCard key={i} className="bg-cyan-500/20 rounded-lg p-3 border border-cyan-500/30" />
))}
</div>
)}
</div>
</div>
{/* 右侧:摄影机运动和叙事逻辑 */}
<div className="space-y-4 overflow-y-auto">
{/* 摄影机运动设计 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Camera} isActive={!currentContent.cameraMovement && isPlaying} color="#06b6d4" />
</h3>
<div className="space-y-3">
{currentContent.cameraMovement ? (
currentContent.cameraMovement.map((move) => (
<ContentCard
key={move.stableId}
className="bg-cyan-400/20 rounded-lg p-3"
>
<div className="text-cyan-200 font-medium text-sm mb-1">{move.type}</div>
<div className="text-gray-300 text-xs mb-2">
<TypewriterText text={move.purpose} stableId={`${move.stableId}-purpose`} />
</div>
<div className="text-cyan-300 text-xs">
<TypewriterText text={move.application} stableId={`${move.stableId}-application`} />
</div>
</ContentCard>
))
) : (
Array.from({length: 3}, (_, i) => (
<SkeletonCard key={i} className="bg-cyan-500/20 rounded-lg p-3 border border-cyan-500/30" />
))
)}
</div>
</div>
{/* 视觉叙事逻辑 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Camera} isActive={!currentContent.visualNarrative && isPlaying} color="#06b6d4" />
</h3>
{currentContent.visualNarrative ? (
<ContentCard className="space-y-3">
<div>
<div className="text-cyan-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.visualNarrative.logic} stableId={`${currentContent.visualNarrative.stableId}-logic`} />
</div>
</div>
<div>
<div className="text-cyan-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.visualNarrative.progression} stableId={`${currentContent.visualNarrative.stableId}-progression`} />
</div>
</div>
<div>
<div className="text-cyan-300 text-sm font-medium mb-1"></div>
<div className="text-gray-300 text-xs">
<TypewriterText text={currentContent.visualNarrative.emphasis} stableId={`${currentContent.visualNarrative.stableId}-emphasis`} />
</div>
</div>
</ContentCard>
) : (
<div className="space-y-3">
{Array.from({length: 3}, (_, i) => (
<SkeletonCard key={i} className="bg-cyan-500/20 rounded-lg p-3 border border-cyan-500/30" />
))}
</div>
)}
</div>
{/* 剪辑点预设 */}
<div className="bg-black/30 rounded-lg p-4">
<h3 className="text-white font-semibold mb-3 flex items-center space-x-2">
<span></span>
<IconLoading icon={Camera} isActive={!currentContent.editingPoints && isPlaying} color="#06b6d4" />
</h3>
<div className="space-y-2">
{currentContent.editingPoints ? (
currentContent.editingPoints.map((point) => (
<ContentCard
key={point.stableId}
className="bg-cyan-300/20 rounded p-2"
>
<div className="text-cyan-200 text-sm font-medium">{point.moment}</div>
<div className="text-gray-300 text-xs">
<TypewriterText text={point.cut} stableId={point.stableId} />
</div>
</ContentCard>
))
) : (
Array.from({length: 4}, (_, i) => (
<SkeletonCard key={i} className="bg-cyan-500/20 rounded-lg p-3 border border-cyan-500/30" />
))
)}
</div>
</div>
</div>
</div>
);
};
export default StoryboardArtist;