From c83f5a4a7e7558c27e23dad62a00e9e4bd3f07f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Fri, 4 Jul 2025 19:38:29 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=BE=AE=E8=B0=83=E7=A9=BA=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E5=8A=A8=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/common/EmptyStateAnimation.tsx | 57 ++++++++++++------- components/pages/create-to-video2.tsx | 31 +++++++--- .../pages/work-flow/use-workflow-data.tsx | 2 +- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/components/common/EmptyStateAnimation.tsx b/components/common/EmptyStateAnimation.tsx index a6d377c..7d9c902 100644 --- a/components/common/EmptyStateAnimation.tsx +++ b/components/common/EmptyStateAnimation.tsx @@ -586,10 +586,9 @@ const ImageQueue = ({ shouldStart, onComplete }: { shouldStart: boolean; onCompl const containers = Array.from(imagesRef.current.children) as HTMLElement[]; const videos = containers.map(container => container.querySelector('video')).filter(Boolean) as HTMLVideoElement[]; - if (videos.length > 0) { + const finalVideoContainer = document.getElementById('final-video-container') as HTMLDivElement; + if (videos.length > 0 && finalVideoContainer) { // 创建最终的大视频容器 - const finalVideoContainer = document.createElement('div'); - finalVideoContainer.className = 'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] rounded-lg overflow-hidden shadow-2xl opacity-0'; const finalVideo = document.createElement('video'); finalVideo.src = finalVideoUrl; @@ -600,7 +599,6 @@ const ImageQueue = ({ shouldStart, onComplete }: { shouldStart: boolean; onCompl finalVideo.className = 'w-full h-full object-cover'; finalVideoContainer.appendChild(finalVideo); - document.body.appendChild(finalVideoContainer); finalVideoContainerRef.current = finalVideoContainer; // 等待最终视频准备就绪 @@ -821,7 +819,7 @@ const ImageQueue = ({ shouldStart, onComplete }: { shouldStart: boolean; onCompl }; // 主要的空状态动画组件 -export const EmptyStateAnimation = () => { +export const EmptyStateAnimation = ({className}: {className: string}) => { const [showText, setShowText] = useState(false); const [showImages, setShowImages] = useState(false); const [animationCycle, setAnimationCycle] = useState(0); @@ -829,21 +827,40 @@ export const EmptyStateAnimation = () => { // 全局清理函数 const globalCleanup = () => { - // 清理所有可能的最终视频容器 - const existingFinalVideos = document.querySelectorAll('div[class*="fixed"][class*="top-1/2"][class*="w-[400px]"]'); - existingFinalVideos.forEach(container => { - if (container.parentNode === document.body) { - container.remove(); + // 清理最终视频容器中的视频元素 + const finalVideoContainer = document.getElementById('final-video-container') as HTMLDivElement; + if (finalVideoContainer) { + const finalVideo = finalVideoContainer.querySelector('video'); + if (finalVideo) { + finalVideo.remove(); + } + // 重置容器透明度 + finalVideoContainer.style.opacity = '0'; + } + + // 清理所有图片容器中的视频元素 + const allVideoElements = document.querySelectorAll('video'); + allVideoElements.forEach(video => { + // 确保视频不是在final-video-container中(已经处理过了) + if (!finalVideoContainer?.contains(video)) { + // 停止播放并移除 + video.pause(); + video.removeAttribute('src'); + video.load(); // 释放资源 + video.remove(); } }); - - // 清理所有body下的视频相关元素 - const bodyChildren = Array.from(document.body.children); - bodyChildren.forEach(child => { - if (child instanceof HTMLElement && - (child.querySelector('video') || child.tagName === 'VIDEO')) { - child.remove(); - } + + // 清理任何可能遗留的视频容器 + const imageContainers = document.querySelectorAll('[class*="w-[200px]"][class*="h-[150px]"]'); + imageContainers.forEach(container => { + const videos = container.querySelectorAll('video'); + videos.forEach(video => { + video.pause(); + video.removeAttribute('src'); + video.load(); + video.remove(); + }); }); }; @@ -899,7 +916,7 @@ export const EmptyStateAnimation = () => { } return ( -
+
{showText && ( { onComplete={handleImagesComplete} /> )} + +
); }; \ No newline at end of file diff --git a/components/pages/create-to-video2.tsx b/components/pages/create-to-video2.tsx index 1597a95..713a89f 100644 --- a/components/pages/create-to-video2.tsx +++ b/components/pages/create-to-video2.tsx @@ -79,7 +79,17 @@ export function CreateToVideo2() { const [episodeId, setEpisodeId] = useState(0); const [isCreating, setIsCreating] = useState(false); const [generatedVideoList, setGeneratedVideoList] = useState([]); - const [projectName, setProjectName] = useState(localStorage.getItem('projectName') || '默认名称'); + const [projectName, setProjectName] = useState('默认名称'); + + // 在客户端挂载后读取localStorage + useEffect(() => { + if (typeof window !== 'undefined') { + const savedProjectName = localStorage.getItem('projectName'); + if (savedProjectName) { + setProjectName(savedProjectName); + } + } + }, []); const handleUploadVideo = async () => { console.log('upload video'); @@ -344,15 +354,19 @@ export function CreateToVideo2() { if (status === 'finished' || status === 'skipped') { setRunTour(false); // 可以在这里存储用户已完成引导的状态 - localStorage.setItem('hasCompletedTour', 'true'); + if (typeof window !== 'undefined') { + localStorage.setItem('hasCompletedTour', 'true'); + } } }; // 检查是否需要显示引导 useEffect(() => { - const hasCompletedTour = localStorage.getItem('hasCompletedTour'); - if (hasCompletedTour) { - setRunTour(false); + if (typeof window !== 'undefined') { + const hasCompletedTour = localStorage.getItem('hasCompletedTour'); + if (hasCompletedTour) { + setRunTour(false); + } } }, []); @@ -363,8 +377,7 @@ export function CreateToVideo2() { return (
{isClient && ( {/* 空状态 */} - + {/* 工具栏 */}
-
+
{isExpanded ? (
setIsExpanded(false)}> {/* 图标 展开按钮 */} diff --git a/components/pages/work-flow/use-workflow-data.tsx b/components/pages/work-flow/use-workflow-data.tsx index e112ae6..b691276 100644 --- a/components/pages/work-flow/use-workflow-data.tsx +++ b/components/pages/work-flow/use-workflow-data.tsx @@ -246,7 +246,7 @@ export function useWorkflowData() { setIsLoading(true); setCurrentLoadingText('正在初始化工作流...'); - const taskId = localStorage.getItem("taskId") || "taskId-123"; + const taskId = (typeof window !== 'undefined' ? localStorage.getItem("taskId") : null) || "taskId-123"; // 首先加载数据 await loadMockData(); From 6e6bdebb649c8b3e0dc283e1c0939f18ef26074c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Fri, 4 Jul 2025 20:53:50 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=A1=B5=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/pages/style/login.css | 199 +++++++++++++++++++++++++++ components/vanta-halo-background.tsx | 10 +- 2 files changed, 204 insertions(+), 5 deletions(-) diff --git a/components/pages/style/login.css b/components/pages/style/login.css index b43e3ff..855af31 100644 --- a/components/pages/style/login.css +++ b/components/pages/style/login.css @@ -299,4 +299,203 @@ .login-logo:hover::before { opacity: 1; +} + +/* 响应式设计 - 移动端和平板端适配 */ +@media (max-width: 1024px) { + .main-container { + position: relative; + } + + .left-panel { + width: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 1; + } + + .right-panel { + width: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 2; + background: transparent; + backdrop-filter: none; + justify-content: flex-end; + align-items: center; + padding: 1rem; + padding-right: 2rem; + } + + .auth-container { + /* max-width: 350px; */ + margin-right: 0; + margin-left: auto; + } + + .login-logo { + top: 1.5rem; + left: 1.5rem; + font-size: 1.5rem; + } + + /* 移动端文字颜色调整 */ + .auth-header h2 { + background: linear-gradient(135deg, #000, #333); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + color: #000; + } + + .auth-header p { + color: rgba(0, 0, 0, 0.7); + } + + .form-label { + color: rgba(0, 0, 0, 0.8); + } + + .form-control { + color: #000; + } + + .form-control::placeholder { + color: rgba(0, 0, 0, 0.4); + } + + /* 注册链接改为橙色 */ + .auth-link { + color: #35daff; + } + + .auth-link:hover { + color: #47dafb; + } + + /* 其他文字元素 */ + .text-red-500 { + color: #dc2626 !important; + } + + .text-green-300 { + color: #86efac !important; + } + + /* 底部提示文字 */ + .text-center p { + color: rgba(0, 0, 0, 0.6) !important; + } + + /* 忘记密码链接也改为橙色 */ + .auth-link.small { + color: #35daff; + } + + .auth-link.small:hover { + color: #47dafb; + } + + /* Google登录按钮文字保持白色 */ + button[type="button"] span { + color: white; + } + + /* 分割线文字 */ + .text-gray-400 { + color: rgba(0, 0, 0, 0.5) !important; + } +} + +@media (max-width: 768px) { + .right-panel { + justify-content: center; + align-items: center; + padding: 1rem; + } + + .auth-container { + max-width: 100%; + width: calc(100% - 2rem); + margin: 0; + padding: 2rem 1.5rem; + } + + .login-logo { + top: 1rem; + left: 1rem; + font-size: 1.3rem; + } + + .auth-header h2 { + font-size: 1.5rem; + } +} + +@media (max-width: 480px) { + .auth-container { + padding: 1.5rem 1rem; + border-radius: 1rem; + } + + .login-logo { + font-size: 1.2rem; + } + + .auth-header { + margin-bottom: 1.5rem; + } + + .auth-header h2 { + font-size: 1.3rem; + } + + .auth-header p { + font-size: 0.8rem; + } + + .form-control { + padding: 0.6rem 0.8rem; + } + + .btn-primary { + padding: 0.6rem; + } +} + +/* 确保背景在所有尺寸下都能正确显示 */ +@media (max-width: 1024px) { + #vanta-background { + width: 100vw !important; + height: 100vh !important; + } +} + +/* iPad横屏特殊处理 */ +@media (max-width: 1024px) and (min-width: 769px) and (orientation: landscape) { + .right-panel { + justify-content: flex-end; + align-items: center; + padding-right: 3rem; + } + + .auth-container { + max-width: 380px; + } +} + +/* 安全区域适配,适用于有刘海的设备 */ +@media (max-width: 1024px) { + .right-panel { + padding-top: max(1rem, env(safe-area-inset-top)); + padding-bottom: max(1rem, env(safe-area-inset-bottom)); + padding-left: max(1rem, env(safe-area-inset-left)); + padding-right: max(2rem, env(safe-area-inset-right)); + } + + .login-logo { + top: max(1rem, calc(env(safe-area-inset-top) + 0.5rem)); + left: max(1rem, calc(env(safe-area-inset-left) + 0.5rem)); + } } \ No newline at end of file diff --git a/components/vanta-halo-background.tsx b/components/vanta-halo-background.tsx index d048ec9..9c78fbd 100644 --- a/components/vanta-halo-background.tsx +++ b/components/vanta-halo-background.tsx @@ -122,11 +122,11 @@ const VantaHaloBackground = memo(({ onLoaded }: VantaHaloBackgroundProps) => {