Files
meijiaka-zy/tauri-app/src/pages/VideoGeneration/_components/AvatarMaterialSelector.tsx
T
小鱼开发 ca4a0b1303 feat: 用户数据隔离、动态分辨率、字幕缩放、多项体验优化
- 用户数据隔离:所有用户数据按 users/{user_id}/ 隔离,Rust IPC 命令自治读取 auth.json
- 安全加固:delete_local_product/rename_local_product/export_product 增加前缀校验
- 移除音调(pitch)功能:从 VoiceSynthesis、projectStore、types 等完全移除
- 动态视频分辨率:根据素材最小高度自动选择 720p/1080p,9:16 比例强校验
- ASS 字幕按目标分辨率等比例缩放(720p 和 1080p 视觉一致)
- Canvas 预览支持参数化 playResY,预览与压制效果一致
- 配音合成增加台词字数校验弹窗(语速>1.0时要求更多字)
- BGM 默认音量从 25% 调至 15%
- 素材选择提示文案更新(9:16 比例,5-60秒)
- 视频校验从严格 1080x1920 改为 9:16 比例判断
- 背景图片弹窗宽度从 440px 放大到 560px
2026-06-04 17:30:54 +08:00

99 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
interface AvatarMaterial {
id: string;
name: string;
duration: number;
path: string;
}
interface AvatarMaterialSelectorProps {
selectedAvatarMaterial: AvatarMaterial | null;
onSelectLocalVideo: () => void;
}
/**
* 人物素材选择卡片
* - 已选择时展示素材信息 + 更换按钮
* - 未选择时展示空状态 + 选择按钮
*/
const AvatarMaterialSelector: React.FC<AvatarMaterialSelectorProps> = ({
selectedAvatarMaterial,
onSelectLocalVideo,
}) => {
return (
<div className="panel-section">
<label className="panel-label"></label>
{selectedAvatarMaterial ? (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: 'var(--spacing-sm) var(--spacing-md)',
border: '1px solid var(--border-color)',
borderRadius: '8px',
background: 'var(--bg-secondary)',
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-sm)' }}>
<div
style={{
width: '36px',
height: '36px',
borderRadius: '50%',
background: 'var(--primary-light)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'var(--primary)',
}}
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
<path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
</div>
<div>
<div style={{ fontSize: 'var(--font-sm)', fontWeight: 500 }}>{selectedAvatarMaterial.name}</div>
<div style={{ fontSize: 'var(--font-xs)', color: 'var(--text-secondary)' }}>
{selectedAvatarMaterial.duration.toFixed(1)}s
</div>
</div>
</div>
<button className="btn btn-ghost btn-sm" onClick={onSelectLocalVideo}>
</button>
</div>
) : (
<div
style={{
padding: 'var(--spacing-md)',
border: '1px dashed var(--border-color)',
borderRadius: '8px',
textAlign: 'center',
color: 'var(--text-secondary)',
fontSize: 'var(--font-sm)',
}}
>
<p></p>
<p style={{ marginTop: '4px', fontSize: 'var(--font-xs)', opacity: 0.7 }}>
</p>
<p style={{ marginTop: '4px', fontSize: 'var(--font-xs)', color: 'var(--text-tertiary)' }}>
MP4 / MOV · 5-60 · 9:16720×1280 1080×1920
</p>
<button
className="btn btn-primary btn-sm"
style={{ marginTop: 'var(--spacing-sm)' }}
onClick={onSelectLocalVideo}
>
</button>
</div>
)}
</div>
);
};
export default AvatarMaterialSelector;