diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx index 3b80e207d..749d8c2db 100644 --- a/apps/web/src/pages/generate/GeneratePage.tsx +++ b/apps/web/src/pages/generate/GeneratePage.tsx @@ -219,6 +219,8 @@ const GeneratePage: React.FC = () => { progress={step3Preview.progress} videoRatio={videoRatio} onRegenerate={step3Preview.regeneratePreview} + titleText={titleSettings.title} + titleSettings={titleSettings} /> )} diff --git a/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx b/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx index e7cb8d336..6cb865fc7 100644 --- a/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx +++ b/apps/web/src/pages/generate/components/PreviewVideoPanel.tsx @@ -1,10 +1,12 @@ /** * 右侧预览视频面板 * Step3 生成预览后常驻显示预览视频 + * Step4+ 显示标题实时预览 */ import React from "react" import { PlayCircleOutlined, LoadingOutlined } from "@ant-design/icons" import type { PreviewResult, PreviewStatus } from "../hooks/useStep3Preview" +import type { TitleSettings } from "../types" interface PreviewVideoPanelProps { previewStatus: PreviewStatus @@ -13,6 +15,45 @@ interface PreviewVideoPanelProps { progress: number videoRatio: string onRegenerate: () => void + /** 标题文字(Step4 起传入) */ + titleText?: string + /** 标题样式设置(Step4 起传入) */ + titleSettings?: TitleSettings +} + +/** 根据 position 返回垂直对齐样式 */ +const positionAlignStyle = (position: string): React.CSSProperties => { + switch (position) { + case "top": + return { justifyContent: "flex-start", paddingTop: 16 } + case "center": + return { justifyContent: "center" } + case "bottom": + default: + return { justifyContent: "flex-end", paddingBottom: 16 } + } +} + +/** 根据 TitleSettings 生成文字样式 */ +const buildTitleStyle = (settings: TitleSettings): React.CSSProperties => { + const style: React.CSSProperties = { + fontFamily: settings.font, + fontSize: Math.min(settings.size, 36), // 预览区域限制最大字号 + color: settings.color, + fontWeight: settings.bold ? 700 : 400, + fontStyle: settings.italic ? "italic" : "normal", + textAlign: "center", + lineHeight: 1.4, + wordBreak: "break-word", + padding: "0 12px", + } + if (settings.stroke) { + style.WebkitTextStroke = "1px rgba(0,0,0,0.6)" + } + if (settings.shadow) { + style.textShadow = "2px 2px 4px rgba(0,0,0,0.7)" + } + return style } export const PreviewVideoPanel: React.FC = ({ @@ -22,10 +63,13 @@ export const PreviewVideoPanel: React.FC = ({ progress, videoRatio, onRegenerate, + titleText, + titleSettings, }) => { const hasPreview = previewStatus === "ready" && previewResult const isLoading = previewStatus === "pending" || previewStatus === "generating" const isError = previewStatus === "error" + const showTitlePreview = !!titleSettings return (
@@ -84,6 +128,43 @@ export const PreviewVideoPanel: React.FC = ({
)} + {/* 标题实时预览区域 */} + {showTitlePreview && ( +
+
+ 标题预览 +
+
+ + {titleText && titleText.trim() ? titleText : "请选择或输入标题"} + +
+
+ )} + {/* 预览信息 */} {hasPreview && previewResult && (
diff --git a/apps/web/src/pages/generate/hooks/useStep4Title/useTitleStyleUpdaters.ts b/apps/web/src/pages/generate/hooks/useStep4Title/useTitleStyleUpdaters.ts index 4b70269a7..49ef2685d 100644 --- a/apps/web/src/pages/generate/hooks/useStep4Title/useTitleStyleUpdaters.ts +++ b/apps/web/src/pages/generate/hooks/useStep4Title/useTitleStyleUpdaters.ts @@ -15,10 +15,10 @@ export function useTitleStyleUpdaters({ titleSettings, onTitleSettingsChange, }: UseTitleStyleUpdatersOptions) { + /** 匹配预设:只用 color/bold/italic/stroke/shadow,不再匹配 size */ const getActivePreset = (settings: TitleSettings): string | null => { for (const p of TITLE_PRESETS) { if ( - settings.size === p.style.size && settings.color === p.style.color && settings.bold === p.style.bold && settings.italic === p.style.italic && @@ -88,13 +88,13 @@ export function useTitleStyleUpdaters({ onTitleSettingsChange({ ...titleSettings, shadow: !titleSettings.shadow }) }, [titleSettings, onTitleSettingsChange]) + /** 应用预设:只覆盖 color/bold/italic/stroke/shadow,不改变字号 */ const applyPreset = useCallback( (presetKey: string) => { const preset = TITLE_PRESETS.find((p) => p.key === presetKey) if (!preset) return onTitleSettingsChange({ ...titleSettings, - size: preset.style.size, color: preset.style.color, bold: preset.style.bold, italic: preset.style.italic,