import type { RefObject } from "react"; import { Eye } from "lucide-react"; interface SubtitleStyleOption { id: string; label: string; font_family?: string; font_file?: string; font_size?: number; highlight_color?: string; normal_color?: string; stroke_color?: string; stroke_size?: number; letter_spacing?: number; bottom_margin?: number; is_default?: boolean; } interface TitleStyleOption { id: string; label: string; font_family?: string; font_file?: string; font_size?: number; color?: string; stroke_color?: string; stroke_size?: number; letter_spacing?: number; font_weight?: number; top_margin?: number; is_default?: boolean; } interface TitleSubtitlePanelProps { showStylePreview: boolean; onTogglePreview: () => void; videoTitle: string; onTitleChange: (value: string) => void; titleStyles: TitleStyleOption[]; selectedTitleStyleId: string; onSelectTitleStyle: (id: string) => void; titleFontSize: number; onTitleFontSizeChange: (value: number) => void; subtitleStyles: SubtitleStyleOption[]; selectedSubtitleStyleId: string; onSelectSubtitleStyle: (id: string) => void; subtitleFontSize: number; onSubtitleFontSizeChange: (value: number) => void; enableSubtitles: boolean; onToggleSubtitles: (value: boolean) => void; resolveAssetUrl: (path?: string | null) => string | null; getFontFormat: (fontFile?: string) => string; buildTextShadow: (color: string, size: number) => string; previewScale?: number; previewAspectRatio?: string; previewBaseWidth?: number; previewBaseHeight?: number; previewContainerRef?: RefObject; } export function TitleSubtitlePanel({ showStylePreview, onTogglePreview, videoTitle, onTitleChange, titleStyles, selectedTitleStyleId, onSelectTitleStyle, titleFontSize, onTitleFontSizeChange, subtitleStyles, selectedSubtitleStyleId, onSelectSubtitleStyle, subtitleFontSize, onSubtitleFontSizeChange, enableSubtitles, onToggleSubtitles, resolveAssetUrl, getFontFormat, buildTextShadow, previewScale = 1, previewAspectRatio = '16 / 9', previewBaseWidth = 1280, previewBaseHeight = 720, previewContainerRef, }: TitleSubtitlePanelProps) { const activeSubtitleStyle = subtitleStyles.find((s) => s.id === selectedSubtitleStyleId) || subtitleStyles.find((s) => s.is_default) || subtitleStyles[0]; const activeTitleStyle = titleStyles.find((s) => s.id === selectedTitleStyleId) || titleStyles.find((s) => s.is_default) || titleStyles[0]; const previewTitleText = videoTitle.trim() || "这里是标题预览"; const subtitleHighlightText = "最近,一个叫Cloudbot"; const subtitleNormalText = "的开源项目在GitHub上彻底火了"; const subtitleHighlightColor = activeSubtitleStyle?.highlight_color || "#FFE600"; const subtitleNormalColor = activeSubtitleStyle?.normal_color || "#FFFFFF"; const subtitleStrokeColor = activeSubtitleStyle?.stroke_color || "#000000"; const subtitleStrokeSize = activeSubtitleStyle?.stroke_size ?? 3; const subtitleLetterSpacing = activeSubtitleStyle?.letter_spacing ?? 2; const subtitleBottomMargin = activeSubtitleStyle?.bottom_margin ?? 0; const subtitleFontFamilyName = `SubtitlePreview-${activeSubtitleStyle?.id || "default"}`; const subtitleFontUrl = activeSubtitleStyle?.font_file ? resolveAssetUrl(`fonts/${activeSubtitleStyle.font_file}`) : null; const titleColor = activeTitleStyle?.color || "#FFFFFF"; const titleStrokeColor = activeTitleStyle?.stroke_color || "#000000"; const titleStrokeSize = activeTitleStyle?.stroke_size ?? 8; const titleLetterSpacing = activeTitleStyle?.letter_spacing ?? 4; const titleTopMargin = activeTitleStyle?.top_margin ?? 0; const titleFontWeight = activeTitleStyle?.font_weight ?? 900; const titleFontFamilyName = `TitlePreview-${activeTitleStyle?.id || "default"}`; const titleFontUrl = activeTitleStyle?.font_file ? resolveAssetUrl(`fonts/${activeTitleStyle.font_file}`) : null; return (

🎬 标题与字幕

{showStylePreview && (
{(titleFontUrl || subtitleFontUrl) && ( )}
{previewTitleText}
{enableSubtitles ? ( <> {subtitleHighlightText} {subtitleNormalText} ) : ( 字幕已关闭 )}
)}
onTitleChange(e.target.value)} placeholder="输入视频标题,将在片头显示" className="w-full px-3 sm:px-4 py-2 text-sm sm:text-base bg-black/30 border border-white/10 rounded-xl text-white placeholder-gray-500 focus:outline-none focus:border-purple-500 transition-colors" />
{titleStyles.length > 0 && (
{titleStyles.map((style) => ( ))}
onTitleFontSizeChange(parseInt(e.target.value, 10))} className="w-full accent-purple-500" />
)} {enableSubtitles && subtitleStyles.length > 0 && (
{subtitleStyles.map((style) => ( ))}
onSubtitleFontSizeChange(parseInt(e.target.value, 10))} className="w-full accent-purple-500" />
)}
逐字高亮字幕

自动生成卡拉OK效果字幕

); }