forked from 77media/video-flow
Merge remote-tracking branch 'origin/dev' into pre
This commit is contained in:
commit
1683befd12
@ -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 (
|
||||
<div className='flex flex-col justify-center items-center'>
|
||||
<div className={`${className} flex flex-col justify-center items-center`}>
|
||||
{showText && (
|
||||
<AnimatedText
|
||||
key={`text-${animationCycle}`}
|
||||
@ -915,6 +932,8 @@ export const EmptyStateAnimation = () => {
|
||||
onComplete={handleImagesComplete}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div id="final-video-container" 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"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -79,7 +79,17 @@ export function CreateToVideo2() {
|
||||
const [episodeId, setEpisodeId] = useState<number>(0);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [generatedVideoList, setGeneratedVideoList] = useState<any[]>([]);
|
||||
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 (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="container mx-auto overflow-hidden custom-scrollbar"
|
||||
style={isExpanded ? { height: 'calc(100vh - 12rem)' } : { height: 'calc(100vh - 20rem)' }}
|
||||
className="container mx-auto overflow-hidden custom-scrollbar h-[calc(100vh-10rem)]"
|
||||
>
|
||||
{isClient && (
|
||||
<JoyrideNoSSR
|
||||
@ -398,10 +411,10 @@ export function CreateToVideo2() {
|
||||
)}
|
||||
<div className='min-h-[100%] flex flex-col justify-center items-center'>
|
||||
{/* 空状态 */}
|
||||
<EmptyStateAnimation />
|
||||
<EmptyStateAnimation className='h-[calc(100vh - 20rem)]' />
|
||||
{/* 工具栏 */}
|
||||
<div className='video-tool-component relative w-[1080px]'>
|
||||
<div className='video-storyboard-tools grid gap-4 rounded-[20px] bg-[#0C0E11] backdrop-blur-[15px]'>
|
||||
<div className='video-storyboard-tools grid gap-4 rounded-[20px] bg-white/[0.08] backdrop-blur-[20px] border border-white/[0.12] shadow-[0_8px_32px_rgba(0,0,0,0.3)]'>
|
||||
{isExpanded ? (
|
||||
<div className='absolute top-0 bottom-0 left-0 right-0 z-[1] grid justify-items-center place-content-center rounded-[20px] bg-[#191B1E] bg-opacity-[0.3] backdrop-blur-[1.5px] cursor-pointer' onClick={() => setIsExpanded(false)}>
|
||||
{/* 图标 展开按钮 */}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -122,11 +122,11 @@ const VantaHaloBackground = memo(({ onLoaded }: VantaHaloBackgroundProps) => {
|
||||
<div
|
||||
ref={vantaRef}
|
||||
style={{
|
||||
width: '61.8vw',
|
||||
height: '100vh',
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
// position: 'fixed',
|
||||
// top: 0,
|
||||
// left: 0,
|
||||
zIndex: -1,
|
||||
willChange: 'transform', // 优化图层合成
|
||||
transform: 'translateZ(0)', // 启用硬件加速
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user