fix: update TemplateCard component by removing unused state and handlers
This commit is contained in:
parent
c714e78ecb
commit
941c143c6b
|
|
@ -12,7 +12,7 @@
|
|||
"scripts": {
|
||||
"claude": "claude --dangerously-skip-permissions",
|
||||
"prepare": "husky",
|
||||
"dev": "vite",
|
||||
"dev": "vite --host 0.0.0.0 --port 3000",
|
||||
"build": "vite build",
|
||||
"build:check": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useState, useRef, useMemo } from 'react';
|
||||
import { useRef, useMemo } from 'react';
|
||||
import { Template } from '../../store/types';
|
||||
import { useI18n } from '../../hooks/useI18n';
|
||||
import './index.css';
|
||||
|
||||
interface TemplateCardProps {
|
||||
|
|
@ -9,10 +8,6 @@ interface 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 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 || '');
|
||||
}, [template.outputExampleUrl]);
|
||||
|
||||
// 检测input是否为视频
|
||||
const isInputVideo = useMemo(() => {
|
||||
return /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(template.inputExampleUrl || ``);
|
||||
}, [template.inputExampleUrl]);
|
||||
|
||||
const handleClick = () => {
|
||||
if (!isDragging) {
|
||||
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); // 延迟重置,避免触发点击
|
||||
onClick(template);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="template-card" onClick={handleClick}>
|
||||
{/* 根据output类型显示不同的内容 */}
|
||||
{isOutputVideo ? (
|
||||
// 当output是视频时,只显示单个视频
|
||||
<div className="single-video-container">
|
||||
<img className="video-poster" src={template.inputExampleUrl || ``} alt="poster" />
|
||||
<video className="single-video" src={template.outputExampleUrl || ``} autoPlay muted loop style={{ objectFit: 'cover' }} controls={false} />
|
||||
{/* 模板名称悬浮 - 视频底部 */}
|
||||
{/* <div className="name-overlay">
|
||||
<span className="name-badge">✨{template.name}</span>
|
||||
</div> */}
|
||||
<video
|
||||
className="single-video"
|
||||
src={template.outputExampleUrl || ``}
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
webkit-playsinline="true"
|
||||
style={{ objectFit: 'cover' }}
|
||||
controls={false}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<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">
|
||||
<img className="full-image" src={template.outputExampleUrl || ``} alt="output" loading="lazy" />
|
||||
</div>
|
||||
|
||||
{/* 模板名称悬浮 - 图片底部 */}
|
||||
{/* <div className="name-overlay">
|
||||
<span className="name-badge">✨{template.name}</span>
|
||||
</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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ export default function Home() {
|
|||
const dispatch = useAppDispatch();
|
||||
const templates = useAppSelector(selectTemplates);
|
||||
const serverSdk = useServerSdk();
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
const loadTemplates = async () => {
|
||||
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(() => {
|
||||
// 需要先检查是否有模板配置文件
|
||||
loadTemplates();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,16 @@ const SuccessComponent: React.FC<SuccessComponentProps> = ({ task }) => {
|
|||
<div className="result-container">
|
||||
{task?.outputUrl ? (
|
||||
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" />
|
||||
)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@
|
|||
height: 70vh;
|
||||
object-fit: contain;
|
||||
border-radius: 12px;
|
||||
transform: translateZ(0);
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
/* 底部操作区域 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue