afcfcf45ee
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 19s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 13s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 14s
CI/CD Pipeline / Build Staging API Image (push) Successful in 46s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m39s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m19s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m50s
CI/CD Pipeline / Validate - Style (push) Has been cancelled
CI/CD Pipeline / Validate - Security (push) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 43h10m14s
CI/CD Pipeline / PR Build Web Image (push) Failing after 43h11m24s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 43h10m56s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 43h9m45s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 43h10m55s
CI/CD Pipeline / PR Build API Image (push) Failing after 43h10m55s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 43h9m45s
CI/CD Pipeline / Frontend Lint (push) Failing after 43h10m50s
fix(frontend): #1896 删除侵权华康字体修复PreviewPlayer字体映射 问题: 1. "华康俪金黑"@font-face字体文件缺失(404)且有版权风险 2. PreviewPlayer直接用中文font_preset/font作为fontFamily,浏览器不识别 修改: - 删除"华康俪金黑"字体选项(FONT_OPTIONS+FONT_FAMILY_MAP)和@font-face声明 - 统一 editing-planner/constants/clipProperties.ts 和 subtitleStyle.ts 从 generate/constants 重新导出 FONT_OPTIONS,避免多处维护 - PreviewPlayer.tsx 标题/字幕 fontFamily 通过 getFontFamily() 映射为浏览器可识别字体栈 - FrontendPreviewPlayer.tsx 标题 fontFamily 同样通过 getFontFamily() 映射 - TitleStylePanel/PanelTitleConfig/SubtitleStylePanel 等组件因复用统一常量自动生效 - 最终保留5个字体:思源黑体、思源宋体、苹方、微软雅黑、楷体 - PingFang 别名保留在 FONT_FAMILY_MAP 中以兼容旧数据,但不在 UI 选项中显示 Refs #1896
131 lines
3.9 KiB
TypeScript
131 lines
3.9 KiB
TypeScript
/**
|
|
* 预览区 — V8 原型 1:1 还原
|
|
* 手机模型预览
|
|
*/
|
|
import React from "react"
|
|
import type { ClipData, ClipType } from "../types"
|
|
import type { TitleConfig } from "@/api/template-editor"
|
|
import { getFontFamily } from "@/pages/generate/constants"
|
|
|
|
interface SubtitleSettings {
|
|
enabled: boolean
|
|
position: string
|
|
font: string
|
|
size: number
|
|
animation: string
|
|
}
|
|
|
|
interface PreviewPlayerProps {
|
|
clips: ClipData[]
|
|
selectedClipId: string | null
|
|
isPlaying: boolean
|
|
titleConfig?: TitleConfig
|
|
subtitleSettings?: SubtitleSettings
|
|
onClipSelect: (clipId: string) => void
|
|
onPlayPause: () => void
|
|
}
|
|
|
|
const CLIP_TYPE_ICONS: Record<ClipType, string> = {
|
|
voice: "🎙️",
|
|
pip: "🖼️",
|
|
}
|
|
|
|
const CLIP_TYPE_LABELS: Record<ClipType, string> = {
|
|
voice: "口播",
|
|
pip: "混剪",
|
|
}
|
|
|
|
const PreviewPlayer: React.FC<PreviewPlayerProps> = ({
|
|
clips,
|
|
selectedClipId,
|
|
isPlaying,
|
|
titleConfig,
|
|
subtitleSettings,
|
|
onPlayPause,
|
|
}) => {
|
|
const selectedClip = clips.find((c) => c.id === selectedClipId)
|
|
const displayClip = selectedClip || clips[0]
|
|
|
|
return (
|
|
<div className="ep-preview-area">
|
|
{/* 手机模型预览 */}
|
|
<div className="ep-phone-preview">
|
|
<div className="ep-phone-status-bar">
|
|
<span>9:41</span>
|
|
<span>📶 🔋</span>
|
|
</div>
|
|
<div className="ep-phone-content">
|
|
{displayClip ? (
|
|
<>
|
|
<button className="ep-phone-play-btn" onClick={onPlayPause}>
|
|
{isPlaying ? "⏸" : "▶"}
|
|
</button>
|
|
<div className="ep-phone-progress">
|
|
<div
|
|
className="ep-phone-progress-fill"
|
|
style={{ width: isPlaying ? "45%" : "0%" }}
|
|
/>
|
|
</div>
|
|
<div className="ep-phone-clip-label">
|
|
{CLIP_TYPE_ICONS[displayClip.type] || "🎬"}{" "}
|
|
{CLIP_TYPE_LABELS[displayClip.type] || "片段"}
|
|
</div>
|
|
</>
|
|
) : (
|
|
<span className="ep-phone-empty-hint">暂无片段</span>
|
|
)}
|
|
|
|
{/* 标题实时预览 */}
|
|
{titleConfig && !titleConfig.ai_auto_select && titleConfig.content && (
|
|
<div
|
|
className="ep-preview-title"
|
|
style={{
|
|
fontSize: `${Math.min(titleConfig.font_size, 20)}px`,
|
|
fontFamily: getFontFamily(titleConfig.font_preset),
|
|
fontWeight: "bold",
|
|
fontStyle: "normal",
|
|
textShadow: "2px 2px 4px rgba(0,0,0,0.5)",
|
|
WebkitTextStroke: "1px rgba(0,0,0,0.6)",
|
|
top:
|
|
titleConfig.position === "top"
|
|
? "6.25%"
|
|
: titleConfig.position === "center"
|
|
? "50%"
|
|
: "auto",
|
|
bottom: titleConfig.position === "bottom" ? "30px" : "auto",
|
|
transform: titleConfig.position === "center" ? "translateY(-50%)" : "none",
|
|
color: titleConfig.font_color,
|
|
}}
|
|
>
|
|
{titleConfig.content}
|
|
</div>
|
|
)}
|
|
|
|
{/* 字幕实时预览 */}
|
|
{subtitleSettings?.enabled && (
|
|
<div
|
|
className="ep-preview-subtitle"
|
|
style={{
|
|
fontSize: `${Math.min(subtitleSettings.size, 14)}px`,
|
|
fontFamily: getFontFamily(subtitleSettings.font),
|
|
top:
|
|
subtitleSettings.position === "top"
|
|
? "8px"
|
|
: subtitleSettings.position === "center"
|
|
? "50%"
|
|
: "auto",
|
|
bottom: subtitleSettings.position === "bottom" ? "8px" : "auto",
|
|
transform: subtitleSettings.position === "center" ? "translateY(-50%)" : "none",
|
|
}}
|
|
>
|
|
字幕预览文字
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default PreviewPlayer
|