diff --git a/app/ScreenAdapter.tsx b/app/ScreenAdapter.tsx index 7f9dc2a..ced8453 100644 --- a/app/ScreenAdapter.tsx +++ b/app/ScreenAdapter.tsx @@ -5,11 +5,23 @@ import { createScreenAdapter } from '@/utils/tools'; export function ScreenAdapter() { useEffect(() => { - // 页面加载时应用 - window.addEventListener('load', createScreenAdapter) + console.log('ScreenAdapter: 开始应用屏幕适配'); + + // 页面加载完成后立即应用 + createScreenAdapter(); // 窗口大小改变时重新应用 - window.addEventListener('resize', createScreenAdapter) + const handleResize = () => { + console.log('ScreenAdapter: 窗口大小改变,重新应用适配'); + createScreenAdapter(); + }; + + window.addEventListener('resize', handleResize); + + // 清理函数 + return () => { + window.removeEventListener('resize', handleResize); + }; }, []); return null; // 这个组件不渲染任何内容 diff --git a/app/layout.tsx b/app/layout.tsx index 358bf6c..44acd72 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -18,6 +18,7 @@ export default function RootLayout({ }) { return ( + ); -} \ No newline at end of file +} diff --git a/components/common/TextCanvas.tsx b/components/common/TextCanvas.tsx new file mode 100644 index 0000000..26d93ed --- /dev/null +++ b/components/common/TextCanvas.tsx @@ -0,0 +1,12 @@ +import { useRef } from "react"; + +export function TextCanvas({ + text, + size +}: { + text: string; + size: number; +}) { + const canvasRef = useRef(null); + return ; +} diff --git a/components/layout/dashboard-layout.tsx b/components/layout/dashboard-layout.tsx index 8db859a..8395a88 100644 --- a/components/layout/dashboard-layout.tsx +++ b/components/layout/dashboard-layout.tsx @@ -12,7 +12,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) { const [sidebarCollapsed, setSidebarCollapsed] = useState(true); return ( -
+
setSidebarCollapsed(!sidebarCollapsed)} /> {children} diff --git a/components/layout/top-bar.tsx b/components/layout/top-bar.tsx index 1023125..0098303 100644 --- a/components/layout/top-bar.tsx +++ b/components/layout/top-bar.tsx @@ -1,16 +1,16 @@ "use client"; -import '../pages/style/top-bar.css'; -import { Button } from '@/components/ui/button'; -import { GradientText } from '@/components/ui/gradient-text'; +import "../pages/style/top-bar.css"; +import { Button } from "@/components/ui/button"; +import { GradientText } from "@/components/ui/gradient-text"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { useTheme } from 'next-themes'; +} from "@/components/ui/dropdown-menu"; +import { useTheme } from "next-themes"; import { Sun, Moon, @@ -18,41 +18,64 @@ import { Settings, LogOut, Bell, - PanelsLeftBottom -} from 'lucide-react'; -import { useRouter } from 'next/navigation'; + PanelsLeftBottom, +} from "lucide-react"; +import { usePathname, useRouter } from "next/navigation"; +import { useEffect, useMemo, useState } from "react"; -export function TopBar({ collapsed, onToggleSidebar }: { collapsed: boolean; onToggleSidebar: () => void }) { +export function TopBar({ + collapsed, + onToggleSidebar, +}: { + collapsed: boolean; + onToggleSidebar: () => void; +}) { const { theme, setTheme } = useTheme(); const router = useRouter(); - + const pathname = usePathname(); + const [isLogin, setIsLogin] = useState(false); + useEffect(() => { + const currentUser = localStorage.getItem("currentUser"); + if (JSON.parse(currentUser || "{}")?.token) { + setIsLogin(true); + } else { + setIsLogin(false); + } + }, [pathname]); const handleAnimationEnd = (event: React.AnimationEvent) => { const element = event.currentTarget; - element.classList.remove('on'); + element.classList.remove("on"); }; const handleMouseEnter = (event: React.MouseEvent) => { const element = event.currentTarget; - element.classList.add('on'); + element.classList.add("on"); }; return (
- -
router.push('/')} + {isLogin && ( + + )} +
router.push("/")} onMouseEnter={handleMouseEnter} onAnimationEnd={handleAnimationEnd} >

-

-

-
- {/* Notifications */} - + {isLogin ? ( +
+ {/* Notifications */} + - {/* Theme Toggle */} - {/* */} + {/* Theme Toggle */} + {/* */} - {/* User Menu */} - - - - - - - - Settings - - - - - Log out - - - -
+ {/* User Menu */} + + + + + + + + Settings + + + + + Log out + + + +
+ ) : ( +
+
router.push("/login")} + data-alt="login-button" + style={{ pointerEvents: 'auto' }} + > + Login +
+
router.push("/signup")} + data-alt="signup-button" + style={{ pointerEvents: 'auto' }} + > + Sign up +
+
+ )}
); -} \ No newline at end of file +} diff --git a/components/pages/home-page2.tsx b/components/pages/home-page2.tsx index 1d71cec..f7d6c68 100644 --- a/components/pages/home-page2.tsx +++ b/components/pages/home-page2.tsx @@ -1,211 +1,521 @@ "use client"; -import { useState, useRef, useEffect } from "react"; -import { Table, AlignHorizontalSpaceAround, Loader2, Clapperboard } from "lucide-react"; +import { useState, useRef, useEffect, useMemo } from "react"; +import { + Table, + AlignHorizontalSpaceAround, + Loader2, + Clapperboard, + CircleArrowRight, +} from "lucide-react"; import "./style/home-page2.css"; import { useRouter } from "next/navigation"; -import { VideoCarouselLayout } from '@/components/video-carousel-layout'; -import { VideoGridLayout } from '@/components/video-grid-layout'; +import { Swiper, SwiperSlide } from "swiper/react"; +import "swiper/swiper-bundle.css"; // 引入样式 +import { Autoplay } from "swiper/modules"; + +import { VideoCarouselLayout } from "@/components/video-carousel-layout"; +import { VideoGridLayout } from "@/components/video-grid-layout"; import { motion, AnimatePresence } from "framer-motion"; import { LiquidButton } from "@/components/ui/liquid-glass-button"; import { createScriptProject, - CreateScriptProjectRequest -} from '@/api/script_project'; -import { - ProjectTypeEnum, - ModeEnum, - ResolutionEnum -} from '@/app/model/enums'; -import { - getResourcesList, - Resource -} from '@/api/resources'; + CreateScriptProjectRequest, +} from "@/api/script_project"; +import { ProjectTypeEnum, ModeEnum, ResolutionEnum } from "@/app/model/enums"; +import { getResourcesList, Resource } from "@/api/resources"; +import { Carousel } from "antd"; +import { TextCanvas } from "../common/TextCanvas"; export function HomePage2() { - const router = useRouter(); - const [activeTool, setActiveTool] = useState("stretch"); - const [dropPosition, setDropPosition] = useState<"left" | "right">("left"); - const [isCreating, setIsCreating] = useState(false); - const [createdProjectId, setCreatedProjectId] = useState(null); - const [resources, setResources] = useState([]); - const [isLoadingResources, setIsLoadingResources] = useState(false); - const containerRef = useRef(null); - - // 将资源数据转换为视频格式 - const videos = resources.map(resource => ({ - id: resource.id.toString(), - url: resource.url, - title: resource.title - })); - - // 获取资源列表 - const fetchResources = async () => { - try { - setIsLoadingResources(true); - const response = await getResourcesList({ published: 1 }); - console.log(response); - if (response.code === 0) { - setResources(response.data); - } else { - console.error('获取资源列表失败:', response.message); - } - } catch (error) { - console.error('获取资源列表出错:', error); - } finally { - setIsLoadingResources(false); - } - }; - - // 组件挂载时获取资源 + const [hPading, setHPading] = useState(0); useEffect(() => { - fetchResources(); + setHPading((window as any).Scale.hScale * 11); }, []); - - // 处理编辑视频 - const handleEdit = (id: string) => { - // TODO: 实现编辑功能 - }; - - // 处理删除视频 - const handleDelete = (id: string) => { - // TODO: 实现删除功能 - }; - - // 处理创建项目 - const handleCreateProject = async () => { - // console.log('isCreating', isCreating); - router.push(`/create`); - // if (isCreating) return; - - // try { - // setIsCreating(true); - // router.push(`/create`); - // return; - - // // 使用默认值 - // const projectType = ProjectTypeEnum.SCRIPT_TO_VIDEO; - - // // 构建项目数据并调用API - // const projectData: CreateScriptProjectRequest = { - // title: "script default", // 默认剧本名称 - // project_type: projectType, - // mode: ModeEnum.MANUAL === 'manual' ? 1 : 2, // 1 表示手动模式,2 表示自动模式 - // resolution: 1080 // 1080p 分辨率 - // }; - - // const projectResponse = await createScriptProject(projectData); - - // if (projectResponse.code === 0 && projectResponse.data.id) { - // const projectId = projectResponse.data.id; - // setCreatedProjectId(projectId); - // // projectId 作为参数传递给 create 页面 - // router.push(`/create?projectId=${projectId}`); - // } else { - // alert(`创建项目失败: ${projectResponse.message}`); - // } - // } catch (error) { - // alert("创建项目时发生错误,请稍后重试"); - // } finally { - // setIsCreating(false); - // } - }; - - // 处理工具切换 - const handleToolChange = (position: "left" | "right") => { - setDropPosition(position); - setActiveTool(position === "left" ? "stretch" : "table"); - }; - return ( -
-
- {/* 工具栏-列表形式切换 */} -
- { - e.stopPropagation(); - handleToolChange(activeTool === "stretch" ? "right" : "left"); - }} - > -
-
- -
-
- - - {/* 水滴动画 */} - - - - - - + // +
+ + + + + + +
+ ); +} - {/* 屏风式视频布局 */} +/** 首屏 */ +function HomeModule1() { + const router = useRouter(); + return ( +
+ +
+

+ Ideas Become Movies +

+

+ Next-Generation AI Movies Making Platform +

+

+ From Ideas to Movies in just 5-10 minutes +

router.push("/create")} > - + Early Access +
- - {/* 网格式视频布局 */} -
- -
- -
- -
{ - e.stopPropagation(); - handleCreateProject(); - }}> - {isCreating ? ( - - ) : ( - - )} - {isCreating ? "Action..." : "Action"} -
-
-
-
); } +/**核心价值 */ +function HomeModule2() { + return ( +
+
+

+ Just Give Us Your Ideas +

+

+ Input your idea in one sentence and MovieFlow will bring +

+

+ your creativity to life +

+
+
+ +
+
+ ); +} +/**案例展示 */ +function HomeModule3() { + const videoList = [ + [ + "/assets/show (1).mp4", + "/assets/show (2).mp4", + "/assets/show (3).mp4", + "/assets/show (4).mp4", + "/assets/show (5).mp4", + ], + [ + "/assets/show (6).mp4", + "/assets/show (7).mp4", + "/assets/show (8).mp4", + "/assets/show (9).mp4", + "/assets/show (10).mp4", + ], + [ + "/assets/show (11).mp4", + "/assets/show (12).mp4", + "/assets/show (13).mp4", + "/assets/show (14).mp4", + "/assets/show (15).mp4", + ], + ]; + + // 定义内容样式 + const contentStyle: React.CSSProperties = { + height: "100%", + lineHeight: "10rem", + textAlign: "center", + background: "#364d79", + }; + + return ( +
+
+

+ Create Anything +

+

+ MovieFlow can make any kind of film in high quality for you +

+
+ {/* 3x3网格布局 */} +
+ {/* 上方阴影遮罩 - 覆盖整个宽度包括padding */} +
+ + {/* 下方阴影遮罩 - 覆盖整个宽度包括padding */} +
+ + {videoList.map((column, columnIndex) => ( +
+ + {column.map((video, videoIndex) => ( + +
+
+
+ ))} +
+
+ ))} +
+
+ ); +} +/**电影制作工序介绍 */ +function HomeModule4() { + const [activeTab, setActiveTab] = useState(0); + + const processSteps = [ + { + title: "Pre-Production", + description: + "Developing the story, writing the script, securing funding, assembling the crew, and planning the shoot.", + }, + { + title: "Production", + description: + "Developing the story, writing the script, securing funding, assembling the crew, and planning the shoot.", + }, + { + title: "Visual Effects", + description: + "Developing the story, writing the script, securing funding, assembling the crew, and planning the shoot.", + }, + { + title: "Voice", + description: + "Developing the story, writing the script, securing funding, assembling the crew, and planning the shoot.", + }, + ]; + + const handleTabClick = (index: number) => { + setActiveTab(index); + }; + + return ( +
+
+

+ Edit like you think +

+
+ +
+ {/* 左侧四个切换tab */} +
+ {processSteps.map((step, index) => ( +
handleTabClick(index)} + className={`w-[31.75rem] h-[10.5rem] rounded-lg cursor-pointer transition-all duration-300 border ${ + activeTab === index + ? "bg-[#262626] border-white/20 hover:border-white/40" + : "bg-black border-white/10 hover:border-white/40" + }`} + > +
+

+ {step.title} +

+

+ {step.description} +

+
+
+ ))} +
+ + {/* 右侧视频播放区域 */} +
+
+
+
+
+
+ ); +} +/**价格方案 */ +function HomeModule5() { + const [billingType, setBillingType] = useState<"monthly" | "yearly">( + "monthly" + ); + + const pricingPlans = [ + { + title: "Plus", + price: billingType === "monthly" ? 28 : 24, + credits: "1x Boost, 10 Credits", + buttonText: "Choose Plus", + features: [ + "10 Credits", + "50 Video mins + 95 iStock", + "2 UGC product asset ads", + "30 secs of generative video", + "2 express clones", + "3 users, 100GB storage", + "Unlimited exports", + ], + }, + { + title: "Max", + price: billingType === "monthly" ? 50 : 43, + credits: "1x Boost, 40 Credits", + buttonText: "Choose Max", + features: [ + "40 Credits", + "50 Video mins + 95 iStock", + "2 UGC product asset ads", + "30 secs of generative video", + "2 express clones", + "3 users, 100GB storage", + "Unlimited exports", + ], + }, + { + title: "Generative", + price: billingType === "monthly" ? 100 : 85, + credits: "1x Boost, 100 Credits", + buttonText: "Choose Generative", + features: [ + "100 Credits", + "50 Video mins + 95 iStock", + "2 UGC product asset ads", + "30 secs of generative video", + "2 express clones", + "3 users, 100GB storage", + "Unlimited exports", + ], + }, + { + title: "Team", + price: billingType === "monthly" ? 899 : 764, + credits: "1x Boost, 1000 Credits", + buttonText: "Choose Team", + features: [ + "1000 Credits", + "50 Video mins + 95 iStock", + "2 UGC product asset ads", + "30 secs of generative video", + "2 express clones", + "3 users, 100GB storage", + "Unlimited exports", + ], + }, + ]; + + return ( +
+
+

+ Start Creating +

+ + {/* 计费切换 */} +
+ + +
+
+ + {/* 主要价格卡片 */} +
+ {pricingPlans.map((plan, index) => ( +
+

+ {plan.title} +

+
+ + ${plan.price} + + /month +
+

+ {plan.credits} +

+ +

+ * Billed monthly until cancelled +

+
    + {plan.features.map((feature, featureIndex) => ( +
  • + + {feature} +
  • + ))} +
+
+ ))} +
+ + {/* 额外价格卡片 */} +
+
+

+ Free +

+
+ $0 +
+

+ 10 Video mins and 1 AI credit per week, 1 Express avatar, 4 Exports + per week with invideo watermark. +

+

+ No access to generative features. +

+ +
+ +
+

+ Enterprise +

+

Custom

+

+ Custom solutions for large organizations. Advanced security and + flexible pricing based on your needs. +

+

+ on your needs. +

+ +
+
+
+ ); +} + +function HomeModule6() { + return ( +
+ © 2025 MovieFlow. All rights reserved. +
+ ); +} diff --git a/package-lock.json b/package-lock.json index 3733755..e710872 100644 --- a/package-lock.json +++ b/package-lock.json @@ -102,7 +102,7 @@ "remark-gfm": "^4.0.1", "sonner": "^1.5.0", "styled-components": "^6.1.19", - "swiper": "^11.2.8", + "swiper": "^11.2.10", "tailwind-merge": "^2.6.0", "tailwindcss": "3.3.3", "tailwindcss-animate": "^1.0.7", @@ -19470,7 +19470,7 @@ }, "node_modules/swiper": { "version": "11.2.10", - "resolved": "https://registry.npmmirror.com/swiper/-/swiper-11.2.10.tgz", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz", "integrity": "sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==", "funding": [ { diff --git a/package.json b/package.json index 7795696..f35775f 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "remark-gfm": "^4.0.1", "sonner": "^1.5.0", "styled-components": "^6.1.19", - "swiper": "^11.2.8", + "swiper": "^11.2.10", "tailwind-merge": "^2.6.0", "tailwindcss": "3.3.3", "tailwindcss-animate": "^1.0.7", diff --git a/public/assets/1.mp4 b/public/assets/1.mp4 new file mode 100644 index 0000000..29055c0 Binary files /dev/null and b/public/assets/1.mp4 differ diff --git a/public/assets/home.mp4 b/public/assets/home.mp4 new file mode 100644 index 0000000..72f55ee Binary files /dev/null and b/public/assets/home.mp4 differ diff --git a/public/assets/show (1).mp4 b/public/assets/show (1).mp4 new file mode 100644 index 0000000..09591d0 Binary files /dev/null and b/public/assets/show (1).mp4 differ diff --git a/public/assets/show (10).mp4 b/public/assets/show (10).mp4 new file mode 100644 index 0000000..0d75d46 Binary files /dev/null and b/public/assets/show (10).mp4 differ diff --git a/public/assets/show (11).mp4 b/public/assets/show (11).mp4 new file mode 100644 index 0000000..f4b8c76 Binary files /dev/null and b/public/assets/show (11).mp4 differ diff --git a/public/assets/show (12).mp4 b/public/assets/show (12).mp4 new file mode 100644 index 0000000..4278bf9 Binary files /dev/null and b/public/assets/show (12).mp4 differ diff --git a/public/assets/show (13).mp4 b/public/assets/show (13).mp4 new file mode 100644 index 0000000..f1e75ed Binary files /dev/null and b/public/assets/show (13).mp4 differ diff --git a/public/assets/show (14).mp4 b/public/assets/show (14).mp4 new file mode 100644 index 0000000..a9ea12c Binary files /dev/null and b/public/assets/show (14).mp4 differ diff --git a/public/assets/show (15).mp4 b/public/assets/show (15).mp4 new file mode 100644 index 0000000..e6005ab Binary files /dev/null and b/public/assets/show (15).mp4 differ diff --git a/public/assets/show (2).mp4 b/public/assets/show (2).mp4 new file mode 100644 index 0000000..7577ef8 Binary files /dev/null and b/public/assets/show (2).mp4 differ diff --git a/public/assets/show (3).mp4 b/public/assets/show (3).mp4 new file mode 100644 index 0000000..2dc6d83 Binary files /dev/null and b/public/assets/show (3).mp4 differ diff --git a/public/assets/show (4).mp4 b/public/assets/show (4).mp4 new file mode 100644 index 0000000..5c261f2 Binary files /dev/null and b/public/assets/show (4).mp4 differ diff --git a/public/assets/show (5).mp4 b/public/assets/show (5).mp4 new file mode 100644 index 0000000..8239c1d Binary files /dev/null and b/public/assets/show (5).mp4 differ diff --git a/public/assets/show (6).mp4 b/public/assets/show (6).mp4 new file mode 100644 index 0000000..ca2ef90 Binary files /dev/null and b/public/assets/show (6).mp4 differ diff --git a/public/assets/show (7).mp4 b/public/assets/show (7).mp4 new file mode 100644 index 0000000..1bb8400 Binary files /dev/null and b/public/assets/show (7).mp4 differ diff --git a/public/assets/show (8).mp4 b/public/assets/show (8).mp4 new file mode 100644 index 0000000..914faaa Binary files /dev/null and b/public/assets/show (8).mp4 differ diff --git a/public/assets/show (9).mp4 b/public/assets/show (9).mp4 new file mode 100644 index 0000000..07f259e Binary files /dev/null and b/public/assets/show (9).mp4 differ diff --git a/utils/tools.ts b/utils/tools.ts index b02e595..444a947 100644 --- a/utils/tools.ts +++ b/utils/tools.ts @@ -45,7 +45,6 @@ export function createScreenAdapter(): void { // 获取当前窗口尺寸 const currentWidth = window.innerWidth; const currentHeight = window.innerHeight; - // 计算缩放比例 (1920x1080) const wScale = currentWidth / 1920; const hScale = currentHeight / 1080; @@ -56,7 +55,10 @@ export function createScreenAdapter(): void { console.error("未找到app节点"); return; } - + (window as any).Scale = { + wScale, + hScale, + }; // 创建样式元素 const style = document.createElement("style");