fix: update TemplateCard component by removing unused state and handlers
This commit is contained in:
parent
c714e78ecb
commit
941c143c6b
|
|
@ -12,7 +12,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"claude": "claude --dangerously-skip-permissions",
|
"claude": "claude --dangerously-skip-permissions",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"dev": "vite",
|
"dev": "vite --host 0.0.0.0 --port 3000",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"build:check": "tsc && vite build",
|
"build:check": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { useState, useRef, useMemo } from 'react';
|
import { useRef, useMemo } from 'react';
|
||||||
import { Template } from '../../store/types';
|
import { Template } from '../../store/types';
|
||||||
import { useI18n } from '../../hooks/useI18n';
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
interface TemplateCardProps {
|
interface TemplateCardProps {
|
||||||
|
|
@ -9,10 +8,6 @@ interface TemplateCardProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TemplateCard({ template, onClick }: TemplateCardProps) {
|
export default function TemplateCard({ template, onClick }: TemplateCardProps) {
|
||||||
const { t } = useI18n();
|
|
||||||
const [splitPosition, setSplitPosition] = useState(50); // 分割线位置百分比
|
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
|
||||||
const [containerInfo, setContainerInfo] = useState<any>(null);
|
|
||||||
const containerRef = useRef<any>(null);
|
const containerRef = useRef<any>(null);
|
||||||
const containerId = `container-${template.code}`; // 为每个容器创建唯一ID
|
const containerId = `container-${template.code}`; // 为每个容器创建唯一ID
|
||||||
|
|
||||||
|
|
@ -21,137 +16,35 @@ export default function TemplateCard({ template, onClick }: TemplateCardProps) {
|
||||||
return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.outputExampleUrl || '');
|
return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.outputExampleUrl || '');
|
||||||
}, [template.outputExampleUrl]);
|
}, [template.outputExampleUrl]);
|
||||||
|
|
||||||
// 检测input是否为视频
|
|
||||||
const isInputVideo = useMemo(() => {
|
|
||||||
return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.inputExampleUrl || ``);
|
|
||||||
}, [template.inputExampleUrl]);
|
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (!isDragging) {
|
onClick(template);
|
||||||
onClick(template);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取容器信息
|
|
||||||
const getContainerInfo = () => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const element = document.getElementById(containerId);
|
|
||||||
if (element) {
|
|
||||||
const rect = element.getBoundingClientRect();
|
|
||||||
setContainerInfo(rect);
|
|
||||||
resolve(rect);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理触摸开始
|
|
||||||
const handleTouchStart = async (e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setIsDragging(true);
|
|
||||||
// 获取容器信息用于后续计算
|
|
||||||
await getContainerInfo();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理触摸移动 - 优化:添加节流,减少计算频率
|
|
||||||
const handleTouchMove = (e: any) => {
|
|
||||||
if (!isDragging || !containerInfo) return;
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
const touch = e.touches[0];
|
|
||||||
if (!touch) return;
|
|
||||||
|
|
||||||
// 使用requestAnimationFrame节流,提升性能
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
// 计算触摸点相对于容器的位置
|
|
||||||
const touchX = touch.clientX - containerInfo.left;
|
|
||||||
const percentage = Math.max(10, Math.min(90, (touchX / containerInfo.width) * 100));
|
|
||||||
|
|
||||||
setSplitPosition(percentage);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理触摸结束
|
|
||||||
const handleTouchEnd = (e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setTimeout(() => setIsDragging(false), 100); // 延迟重置,避免触发点击
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="template-card" onClick={handleClick}>
|
<div className="template-card" onClick={handleClick}>
|
||||||
{/* 根据output类型显示不同的内容 */}
|
|
||||||
{isOutputVideo ? (
|
{isOutputVideo ? (
|
||||||
// 当output是视频时,只显示单个视频
|
|
||||||
<div className="single-video-container">
|
<div className="single-video-container">
|
||||||
<img className="video-poster" src={template.inputExampleUrl || ``} alt="poster" />
|
<img className="video-poster" src={template.inputExampleUrl || ``} alt="poster" />
|
||||||
<video className="single-video" src={template.outputExampleUrl || ``} autoPlay muted loop style={{ objectFit: 'cover' }} controls={false} />
|
<video
|
||||||
{/* 模板名称悬浮 - 视频底部 */}
|
className="single-video"
|
||||||
{/* <div className="name-overlay">
|
src={template.outputExampleUrl || ``}
|
||||||
<span className="name-badge">✨{template.name}</span>
|
autoPlay
|
||||||
</div> */}
|
muted
|
||||||
|
loop
|
||||||
|
playsInline
|
||||||
|
webkit-playsinline="true"
|
||||||
|
style={{ objectFit: 'cover' }}
|
||||||
|
controls={false}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="image-comparison">
|
<div className="image-comparison">
|
||||||
<div id={containerId} className="merged-image-container" ref={containerRef} onTouchMove={handleTouchMove} onTouchEnd={handleTouchEnd}>
|
<div id={containerId} className="merged-image-container" ref={containerRef}>
|
||||||
{/* 效果图层 - 完整图片,通过遮罩显示右半部分 */}
|
|
||||||
<div className="image-layer overlay-layer">
|
<div className="image-layer overlay-layer">
|
||||||
<img className="full-image" src={template.outputExampleUrl || ``} alt="output" loading="lazy" />
|
<img className="full-image" src={template.outputExampleUrl || ``} alt="output" loading="lazy" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 模板名称悬浮 - 图片底部 */}
|
|
||||||
{/* <div className="name-overlay">
|
|
||||||
<span className="name-badge">✨{template.name}</span>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
// 原有的图片对比逻辑
|
|
||||||
// <div className="image-comparison">
|
|
||||||
// <div id={containerId} className="merged-image-container" ref={containerRef} onTouchMove={handleTouchMove} onTouchEnd={handleTouchEnd}>
|
|
||||||
// {/* 原图层 - 完整图片/视频 */}
|
|
||||||
// <div className="image-layer">
|
|
||||||
// {isInputVideo ? (
|
|
||||||
// <video
|
|
||||||
// className="full-video"
|
|
||||||
// src={template.inputExampleUrl || ``}
|
|
||||||
// autoPlay
|
|
||||||
// muted
|
|
||||||
// loop
|
|
||||||
// style={{ objectFit: 'cover' }}
|
|
||||||
// controls={false}
|
|
||||||
// />
|
|
||||||
// ) : (
|
|
||||||
// <img className="full-image" src={template.inputExampleUrl || ``} alt="input" loading="lazy" />
|
|
||||||
// )}
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// {/* 效果图层 - 完整图片,通过遮罩显示右半部分 */}
|
|
||||||
// <div
|
|
||||||
// className="image-layer overlay-layer"
|
|
||||||
// style={{
|
|
||||||
// clipPath: `polygon(${splitPosition}% 0%, 100% 0%, 100% 100%, ${splitPosition}% 100%)`,
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <img className="full-image" src={template.outputExampleUrl || ``} alt="output" loading="lazy" />
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// {/* 可拖拽的分割线 */}
|
|
||||||
// <div
|
|
||||||
// className="split-line"
|
|
||||||
// style={{ left: `${splitPosition}%` }}
|
|
||||||
// onTouchStart={handleTouchStart}
|
|
||||||
// onTouchMove={handleTouchMove}
|
|
||||||
// onTouchEnd={handleTouchEnd}
|
|
||||||
// >
|
|
||||||
// <div className="split-handle">
|
|
||||||
// <span className="split-icon">⟷</span>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// {/* 模板名称悬浮 - 图片底部 */}
|
|
||||||
// <div className="name-overlay">
|
|
||||||
// <span className="name-badge">✨{template.name}</span>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ export default function Home() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const templates = useAppSelector(selectTemplates);
|
const templates = useAppSelector(selectTemplates);
|
||||||
const serverSdk = useServerSdk();
|
const serverSdk = useServerSdk();
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
|
||||||
|
|
||||||
const loadTemplates = async () => {
|
const loadTemplates = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -30,19 +29,6 @@ export default function Home() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 下拉刷新处理
|
|
||||||
const handleRefresh = async () => {
|
|
||||||
setRefreshing(true);
|
|
||||||
try {
|
|
||||||
await loadTemplates();
|
|
||||||
alert(t('home.refreshSuccess'));
|
|
||||||
} catch (error) {
|
|
||||||
console.error(t('home.refreshFailed'), error);
|
|
||||||
} finally {
|
|
||||||
setRefreshing(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 需要先检查是否有模板配置文件
|
// 需要先检查是否有模板配置文件
|
||||||
loadTemplates();
|
loadTemplates();
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,16 @@ const SuccessComponent: React.FC<SuccessComponentProps> = ({ task }) => {
|
||||||
<div className="result-container">
|
<div className="result-container">
|
||||||
{task?.outputUrl ? (
|
{task?.outputUrl ? (
|
||||||
task.outputUrl.includes('.mp4') ? (
|
task.outputUrl.includes('.mp4') ? (
|
||||||
<video className="result-video" src={task.outputUrl} controls autoPlay muted loop />
|
<video
|
||||||
|
className="result-video"
|
||||||
|
src={task.outputUrl}
|
||||||
|
controls
|
||||||
|
autoPlay
|
||||||
|
muted
|
||||||
|
loop
|
||||||
|
playsInline
|
||||||
|
webkit-playsinline="true"
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<img className="result-image" src={`https://mixvideo-workflow.bowong.cc/cdn/${encodeURIComponent(task.outputUrl)}`} alt="Generated result" />
|
<img className="result-image" src={`https://mixvideo-workflow.bowong.cc/cdn/${encodeURIComponent(task.outputUrl)}`} alt="Generated result" />
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
transform: translateZ(0);
|
||||||
|
backface-visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 底部操作区域 */
|
/* 底部操作区域 */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue