forked from 77media/video-flow
前端调整,首页更新
This commit is contained in:
parent
7271f96003
commit
7a68c454eb
@ -5,11 +5,23 @@ import { createScreenAdapter } from '@/utils/tools';
|
|||||||
|
|
||||||
export function ScreenAdapter() {
|
export function ScreenAdapter() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 页面加载时应用
|
console.log('ScreenAdapter: 开始应用屏幕适配');
|
||||||
window.addEventListener('load', createScreenAdapter)
|
|
||||||
|
// 页面加载完成后立即应用
|
||||||
|
createScreenAdapter();
|
||||||
|
|
||||||
// 窗口大小改变时重新应用
|
// 窗口大小改变时重新应用
|
||||||
window.addEventListener('resize', createScreenAdapter)
|
const handleResize = () => {
|
||||||
|
console.log('ScreenAdapter: 窗口大小改变,重新应用适配');
|
||||||
|
createScreenAdapter();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
// 清理函数
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return null; // 这个组件不渲染任何内容
|
return null; // 这个组件不渲染任何内容
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export default function RootLayout({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
|
<meta name="robots" content="noindex"></meta>
|
||||||
<body className="font-sans antialiased">
|
<body className="font-sans antialiased">
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
theme={{
|
theme={{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { DashboardLayout } from '@/components/layout/dashboard-layout';
|
import { DashboardLayout } from "@/components/layout/dashboard-layout";
|
||||||
import { HomePage2 } from '@/components/pages/home-page2';
|
import { HomePage2 } from "@/components/pages/home-page2";
|
||||||
import OAuthCallbackHandler from '@/components/ui/oauth-callback-handler';
|
import OAuthCallbackHandler from "@/components/ui/oauth-callback-handler";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
12
components/common/TextCanvas.tsx
Normal file
12
components/common/TextCanvas.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
|
export function TextCanvas({
|
||||||
|
text,
|
||||||
|
size
|
||||||
|
}: {
|
||||||
|
text: string;
|
||||||
|
size: number;
|
||||||
|
}) {
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
|
return <canvas ref={canvasRef}></canvas>;
|
||||||
|
}
|
||||||
@ -12,7 +12,7 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(true);
|
const [sidebarCollapsed, setSidebarCollapsed] = useState(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background" id="app">
|
<div className=" min-h-screen bg-background" id="app">
|
||||||
<Sidebar collapsed={sidebarCollapsed} onToggle={setSidebarCollapsed} />
|
<Sidebar collapsed={sidebarCollapsed} onToggle={setSidebarCollapsed} />
|
||||||
<TopBar collapsed={sidebarCollapsed} onToggleSidebar={() => setSidebarCollapsed(!sidebarCollapsed)} />
|
<TopBar collapsed={sidebarCollapsed} onToggleSidebar={() => setSidebarCollapsed(!sidebarCollapsed)} />
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import '../pages/style/top-bar.css';
|
import "../pages/style/top-bar.css";
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from "@/components/ui/button";
|
||||||
import { GradientText } from '@/components/ui/gradient-text';
|
import { GradientText } from "@/components/ui/gradient-text";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu';
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { useTheme } from 'next-themes';
|
import { useTheme } from "next-themes";
|
||||||
import {
|
import {
|
||||||
Sun,
|
Sun,
|
||||||
Moon,
|
Moon,
|
||||||
@ -18,34 +18,57 @@ import {
|
|||||||
Settings,
|
Settings,
|
||||||
LogOut,
|
LogOut,
|
||||||
Bell,
|
Bell,
|
||||||
PanelsLeftBottom
|
PanelsLeftBottom,
|
||||||
} from 'lucide-react';
|
} from "lucide-react";
|
||||||
import { useRouter } from 'next/navigation';
|
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 { theme, setTheme } = useTheme();
|
||||||
const router = useRouter();
|
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<HTMLDivElement>) => {
|
const handleAnimationEnd = (event: React.AnimationEvent<HTMLDivElement>) => {
|
||||||
const element = event.currentTarget;
|
const element = event.currentTarget;
|
||||||
element.classList.remove('on');
|
element.classList.remove("on");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseEnter = (event: React.MouseEvent<HTMLDivElement>) => {
|
const handleMouseEnter = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
const element = event.currentTarget;
|
const element = event.currentTarget;
|
||||||
element.classList.add('on');
|
element.classList.add("on");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed right-0 top-0 left-0 h-16 header z-50">
|
<div className="fixed right-0 top-0 left-0 h-16 header z-50">
|
||||||
<div className="h-full flex items-center justify-between pr-6 pl-2">
|
<div className="h-full flex items-center justify-between pr-6 pl-2">
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<Button className='button-NxtqWZ' variant="ghost" size="sm" onClick={onToggleSidebar}>
|
{isLogin && (
|
||||||
<PanelsLeftBottom className="h-4 w-4" />
|
<Button
|
||||||
</Button>
|
className="button-NxtqWZ"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={onToggleSidebar}
|
||||||
|
>
|
||||||
|
<PanelsLeftBottom className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className={`flex items-center cursor-pointer space-x-4 link-logo roll event-on`}
|
className={`flex items-center cursor-pointer space-x-4 link-logo roll event-on`}
|
||||||
onClick={() => router.push('/')}
|
onClick={() => router.push("/")}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onAnimationEnd={handleAnimationEnd}
|
onAnimationEnd={handleAnimationEnd}
|
||||||
>
|
>
|
||||||
@ -72,43 +95,64 @@ export function TopBar({ collapsed, onToggleSidebar }: { collapsed: boolean; onT
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center space-x-4">
|
{isLogin ? (
|
||||||
{/* Notifications */}
|
<div className="flex items-center space-x-4">
|
||||||
<Button variant="ghost" size="sm">
|
{/* Notifications */}
|
||||||
<Bell className="h-4 w-4" />
|
<Button variant="ghost" size="sm">
|
||||||
</Button>
|
<Bell className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
{/* Theme Toggle */}
|
{/* Theme Toggle */}
|
||||||
{/* <Button
|
{/* <Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
|
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
|
||||||
>
|
>
|
||||||
<Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
<Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||||
<Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
<Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||||
</Button> */}
|
</Button> */}
|
||||||
|
|
||||||
{/* User Menu */}
|
{/* User Menu */}
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="ghost" size="sm">
|
<Button variant="ghost" size="sm">
|
||||||
<User className="h-4 w-4" />
|
<User className="h-4 w-4" />
|
||||||
<span className="ml-2">User</span>
|
<span className="ml-2">User</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<Settings className="mr-2 h-4 w-4" />
|
<Settings className="mr-2 h-4 w-4" />
|
||||||
Settings
|
Settings
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<LogOut className="mr-2 h-4 w-4" />
|
<LogOut className="mr-2 h-4 w-4" />
|
||||||
Log out
|
Log out
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center space-x-4" style={{ pointerEvents: 'auto' }}>
|
||||||
|
<div
|
||||||
|
className="flex justify-center items-center text-white text-base w-[100px] h-[40px] cursor-pointer event-on hover:opacity-80 transition-opacity"
|
||||||
|
onClick={() => router.push("/login")}
|
||||||
|
data-alt="login-button"
|
||||||
|
style={{ pointerEvents: 'auto' }}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="flex justify-center items-center text-black text-base bg-white rounded-full w-[100px] h-[40px] cursor-pointer event-on hover:opacity-80 transition-opacity"
|
||||||
|
onClick={() => router.push("/signup")}
|
||||||
|
data-alt="signup-button"
|
||||||
|
style={{ pointerEvents: 'auto' }}
|
||||||
|
>
|
||||||
|
Sign up
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,211 +1,521 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useRef, useEffect } from "react";
|
import { useState, useRef, useEffect, useMemo } from "react";
|
||||||
import { Table, AlignHorizontalSpaceAround, Loader2, Clapperboard } from "lucide-react";
|
import {
|
||||||
|
Table,
|
||||||
|
AlignHorizontalSpaceAround,
|
||||||
|
Loader2,
|
||||||
|
Clapperboard,
|
||||||
|
CircleArrowRight,
|
||||||
|
} from "lucide-react";
|
||||||
import "./style/home-page2.css";
|
import "./style/home-page2.css";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { VideoCarouselLayout } from '@/components/video-carousel-layout';
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
import { VideoGridLayout } from '@/components/video-grid-layout';
|
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 { motion, AnimatePresence } from "framer-motion";
|
||||||
import { LiquidButton } from "@/components/ui/liquid-glass-button";
|
import { LiquidButton } from "@/components/ui/liquid-glass-button";
|
||||||
import {
|
import {
|
||||||
createScriptProject,
|
createScriptProject,
|
||||||
CreateScriptProjectRequest
|
CreateScriptProjectRequest,
|
||||||
} from '@/api/script_project';
|
} from "@/api/script_project";
|
||||||
import {
|
import { ProjectTypeEnum, ModeEnum, ResolutionEnum } from "@/app/model/enums";
|
||||||
ProjectTypeEnum,
|
import { getResourcesList, Resource } from "@/api/resources";
|
||||||
ModeEnum,
|
import { Carousel } from "antd";
|
||||||
ResolutionEnum
|
import { TextCanvas } from "../common/TextCanvas";
|
||||||
} from '@/app/model/enums';
|
|
||||||
import {
|
|
||||||
getResourcesList,
|
|
||||||
Resource
|
|
||||||
} from '@/api/resources';
|
|
||||||
|
|
||||||
export function HomePage2() {
|
export function HomePage2() {
|
||||||
const router = useRouter();
|
const [hPading, setHPading] = useState(0);
|
||||||
const [activeTool, setActiveTool] = useState("stretch");
|
|
||||||
const [dropPosition, setDropPosition] = useState<"left" | "right">("left");
|
|
||||||
const [isCreating, setIsCreating] = useState(false);
|
|
||||||
const [createdProjectId, setCreatedProjectId] = useState<number | null>(null);
|
|
||||||
const [resources, setResources] = useState<Resource[]>([]);
|
|
||||||
const [isLoadingResources, setIsLoadingResources] = useState(false);
|
|
||||||
const containerRef = useRef<HTMLDivElement>(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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 组件挂载时获取资源
|
|
||||||
useEffect(() => {
|
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 (
|
return (
|
||||||
<div className="min-h-screen bg-[var(--background)]" ref={containerRef}>
|
//
|
||||||
<div className="flex relative" style={{height: '100vh'}}>
|
<div
|
||||||
{/* 工具栏-列表形式切换 */}
|
className="w-full h-full overflow-y-auto"
|
||||||
<div className="absolute top-[8rem] z-[50] right-6 w-[128px] flex justify-end">
|
style={{ paddingBottom: `${hPading}rem` }}
|
||||||
<LiquidButton className="w-[128px] h-[3rem] text-sm"
|
>
|
||||||
onClick={(e: React.MouseEvent) => {
|
<HomeModule1 />
|
||||||
e.stopPropagation();
|
<HomeModule2 />
|
||||||
handleToolChange(activeTool === "stretch" ? "right" : "left");
|
<HomeModule3 />
|
||||||
}}
|
<HomeModule4 />
|
||||||
>
|
<HomeModule5 />
|
||||||
<div className="relative flex items-center justify-around gap-4 w-[128px] h-[3rem] p-2">
|
<HomeModule6 />
|
||||||
<div
|
</div>
|
||||||
className={`cursor-pointer relative z-10 transition-opacity duration-300 ${activeTool === "stretch" ? "opacity-100" : "opacity-50"}`}>
|
);
|
||||||
<AlignHorizontalSpaceAround className="w-4 h-4 text-white" />
|
}
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`cursor-pointer relative z-10 transition-opacity duration-300 ${activeTool === "table" ? "opacity-100" : "opacity-50"}`}>
|
|
||||||
<Table className="w-4 h-4 text-white" />
|
|
||||||
</div>
|
|
||||||
{/* 水滴动画 */}
|
|
||||||
<AnimatePresence>
|
|
||||||
<motion.div
|
|
||||||
className="absolute w-[40px] h-8 bg-[rgba(255,255,255,0.35)] rounded-full backdrop-blur-[2px] z-[1]"
|
|
||||||
initial={{ x: dropPosition === "left" ? -32 : 32 }}
|
|
||||||
animate={{
|
|
||||||
x: dropPosition === "left" ? -32 : 32,
|
|
||||||
scale: [1, 1.2, 1],
|
|
||||||
}}
|
|
||||||
transition={{
|
|
||||||
type: "spring",
|
|
||||||
stiffness: 300,
|
|
||||||
damping: 30,
|
|
||||||
scale: {
|
|
||||||
duration: 0.2,
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</AnimatePresence>
|
|
||||||
</div>
|
|
||||||
</LiquidButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 屏风式视频布局 */}
|
/** 首屏 */
|
||||||
|
function HomeModule1() {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<div className="home-module1 relative flex justify-center items-center w-full h-[1280px] bg-black snap-start">
|
||||||
|
<video
|
||||||
|
src="/assets/home.mp4"
|
||||||
|
autoPlay
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
className="absolute top-0 left-0 z-1 w-full h-full object-cover"
|
||||||
|
></video>
|
||||||
|
<div className="center z-10 flex flex-col items-center">
|
||||||
|
<h1 className="text-white text-[5.75rem] leading-[100%] font-bold mb-[5rem]">
|
||||||
|
Ideas Become Movies
|
||||||
|
</h1>
|
||||||
|
<p className="text-white text-[2rem] leading-[140%] font-normal">
|
||||||
|
Next-Generation AI Movies Making Platform
|
||||||
|
</p>
|
||||||
|
<p className="text-white text-[2rem] leading-[140%] font-normal">
|
||||||
|
From Ideas to Movies in just 5-10 minutes
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
className={`absolute w-full h-[calc(100vh - 4rem)] transition-all duration-500
|
className="w-[11.5rem] h-[3.75rem] mt-[4rem] text-base flex justify-center items-center font-normal border border-white rounded-full bg-white/30 cursor-pointer"
|
||||||
${activeTool === "stretch" ? "opacity-100 translate-x-0" : "opacity-0 translate-x-[-100%] pointer-events-none"}
|
onClick={() => router.push("/create")}
|
||||||
`}
|
|
||||||
style={{
|
|
||||||
height: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
marginTop: '4rem'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<VideoCarouselLayout videos={videos} />
|
Early Access
|
||||||
|
<CircleArrowRight className="ml-[1rem]" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 网格式视频布局 */}
|
|
||||||
<div
|
|
||||||
className={`absolute top-[8rem] w-full transition-all duration-500 max-h-[calc(100vh-8rem)] overflow-y-auto hide-scrollbar
|
|
||||||
${activeTool === "table" ? "opacity-100 translate-x-0" : "opacity-0 translate-x-[100%] pointer-events-none"}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<VideoGridLayout
|
|
||||||
videos={videos}
|
|
||||||
onEdit={handleEdit}
|
|
||||||
onDelete={handleDelete}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-[128px] h-[128px] rounded-[50%] overflow-hidden fixed bottom-[3rem] left-[50%] -translate-x-1/2 z-50">
|
|
||||||
<LiquidButton className="w-[128px] h-[128px] text-lg">
|
|
||||||
<div className="flex items-center justify-center gap-2"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleCreateProject();
|
|
||||||
}}>
|
|
||||||
{isCreating ? (
|
|
||||||
<Loader2 className="w-6 h-6 text-white animate-spin" />
|
|
||||||
) : (
|
|
||||||
<Clapperboard className="w-6 h-6 text-white" />
|
|
||||||
)}
|
|
||||||
{isCreating ? "Action..." : "Action"}
|
|
||||||
</div>
|
|
||||||
</LiquidButton>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
/**核心价值 */
|
||||||
|
function HomeModule2() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-alt="core-value-section"
|
||||||
|
className="home-module2 relative flex flex-col items-center justify-center w-full h-[1600px] bg-black snap-start"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-alt="core-value-content"
|
||||||
|
className="center z-10 flex flex-col items-center mb-[14rem]"
|
||||||
|
>
|
||||||
|
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[3rem]">
|
||||||
|
Just Give Us Your Ideas
|
||||||
|
</h2>
|
||||||
|
<p className="text-white text-[1.125rem] leading-[140%] font-normal text-center">
|
||||||
|
Input your idea in one sentence and MovieFlow will bring
|
||||||
|
</p>
|
||||||
|
<p className="text-white text-[1.125rem] leading-[140%] font-normal text-center">
|
||||||
|
your creativity to life
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
data-alt="core-value-video"
|
||||||
|
className="relative w-[80rem] h-[45rem] flex justify-center items-center border border-white/20 rounded-lg overflow-hidden"
|
||||||
|
>
|
||||||
|
<video
|
||||||
|
src="/assets/1.mp4"
|
||||||
|
autoPlay
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
></video>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**案例展示 */
|
||||||
|
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 (
|
||||||
|
<div className="home-module3 h-[1666px] relative flex flex-col items-center justify-center w-full bg-black snap-start">
|
||||||
|
<div className="center z-10 flex flex-col items-center mb-[14rem]">
|
||||||
|
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[3rem]">
|
||||||
|
Create Anything
|
||||||
|
</h2>
|
||||||
|
<p className="text-white text-[1.125rem] leading-[140%] font-normal text-center">
|
||||||
|
MovieFlow can make any kind of film in high quality for you
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{/* 3x3网格布局 */}
|
||||||
|
<div
|
||||||
|
data-alt="vertical-grid-shadow"
|
||||||
|
className="grid grid-cols-3 gap-[1rem] w-full h-[64rem] px-[5rem] relative"
|
||||||
|
>
|
||||||
|
{/* 上方阴影遮罩 - 覆盖整个宽度包括padding */}
|
||||||
|
<div className="absolute -top-[0.0625rem] -left-0 w-full h-[6rem] bg-gradient-to-b from-black via-black/30 to-transparent z-20 pointer-events-none"></div>
|
||||||
|
|
||||||
|
{/* 下方阴影遮罩 - 覆盖整个宽度包括padding */}
|
||||||
|
<div className="absolute -bottom-[0.0625rem] -left-0 w-full h-[6rem] bg-gradient-to-t from-black via-black/30 to-transparent z-20 pointer-events-none"></div>
|
||||||
|
|
||||||
|
{videoList.map((column, columnIndex) => (
|
||||||
|
<div
|
||||||
|
key={columnIndex}
|
||||||
|
className="w-[35.5rem] h-[64rem] relative z-10"
|
||||||
|
>
|
||||||
|
<Swiper
|
||||||
|
modules={[Autoplay]}
|
||||||
|
direction="vertical"
|
||||||
|
loop={true}
|
||||||
|
spaceBetween={0}
|
||||||
|
slidesPerView={3}
|
||||||
|
autoplay={{
|
||||||
|
delay: 0,
|
||||||
|
pauseOnMouseEnter: true,
|
||||||
|
disableOnInteraction: false,
|
||||||
|
reverseDirection: columnIndex % 2 === 0,
|
||||||
|
}}
|
||||||
|
speed={6000}
|
||||||
|
grabCursor={true}
|
||||||
|
className="w-full h-full"
|
||||||
|
cssMode={false}
|
||||||
|
freeMode={true}
|
||||||
|
watchSlidesProgress={false}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"--swiper-wrapper-transition-timing-function": "linear",
|
||||||
|
} as React.CSSProperties
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{column.map((video, videoIndex) => (
|
||||||
|
<SwiperSlide key={videoIndex}>
|
||||||
|
<div className="w-full h-[20rem] bg-gray-800 rounded-2xl overflow-hidden">
|
||||||
|
<video
|
||||||
|
src={video}
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
onMouseEnter={(e) => {
|
||||||
|
const videoElement = e.currentTarget;
|
||||||
|
videoElement.play();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SwiperSlide>
|
||||||
|
))}
|
||||||
|
</Swiper>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**电影制作工序介绍 */
|
||||||
|
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 (
|
||||||
|
<div
|
||||||
|
data-alt="core-value-section"
|
||||||
|
className="home-module4 h-[1280px] relative flex flex-col items-center justify-center w-full bg-black snap-start"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-alt="core-value-content"
|
||||||
|
className="center z-10 flex flex-col items-center mb-[14rem]"
|
||||||
|
>
|
||||||
|
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[3rem]">
|
||||||
|
Edit like you think
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex w-full px-[4rem] gap-[2rem]">
|
||||||
|
{/* 左侧四个切换tab */}
|
||||||
|
<div className="flex flex-col gap-[1rem]">
|
||||||
|
{processSteps.map((step, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
onClick={() => 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"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="p-[1.5rem] h-full flex flex-col justify-center">
|
||||||
|
<h3
|
||||||
|
className={`text-[2rem] font-normal mb-[1.5rem] ${
|
||||||
|
activeTab === index ? "text-white" : "text-white/70"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{step.title}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
className={`text-[0.875rem] leading-[140%] ${
|
||||||
|
activeTab === index ? "text-white" : "text-white/70"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{step.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 右侧视频播放区域 */}
|
||||||
|
<div className="flex-1 flex justify-center">
|
||||||
|
<div className="w-[80rem] h-[45rem] bg-gray-800 rounded-lg overflow-hidden border border-white/20">
|
||||||
|
<video
|
||||||
|
key={activeTab}
|
||||||
|
src="/assets/home.mp4"
|
||||||
|
autoPlay
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
playsInline
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**价格方案 */
|
||||||
|
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 (
|
||||||
|
<div
|
||||||
|
data-alt="core-value-section"
|
||||||
|
className="home-module5 h-[1600px] relative flex flex-col items-center justify-center w-full bg-black snap-start"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-alt="core-value-content"
|
||||||
|
className="center z-10 flex flex-col items-center mb-[8rem]"
|
||||||
|
>
|
||||||
|
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[1.5rem]">
|
||||||
|
Start Creating
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{/* 计费切换 */}
|
||||||
|
<div className="h-[3.375rem] flex bg-black rounded-full p-[0.0625rem] mt-[1.5rem] border border-white/20">
|
||||||
|
<button
|
||||||
|
onClick={() => setBillingType("monthly")}
|
||||||
|
className={`box-border flex justify-center items-center w-[6rem] text-base rounded-full transition-all duration-300 ${
|
||||||
|
billingType === "monthly"
|
||||||
|
? "bg-white text-black"
|
||||||
|
: "text-white hover:text-gray-300"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Monthly
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setBillingType("yearly")}
|
||||||
|
className={`box-border flex justify-center items-center w-[7.125rem] text-base rounded-full transition-all duration-300 ${
|
||||||
|
billingType === "yearly"
|
||||||
|
? "bg-white text-black"
|
||||||
|
: "text-white hover:text-gray-300"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Yearly - <span className="text-[#FFCC6D]">15%</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 主要价格卡片 */}
|
||||||
|
<div className="grid grid-cols-4 gap-[1.5rem] w-full px-[12rem] mb-[2rem]">
|
||||||
|
{pricingPlans.map((plan, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className=" h-[38.125rem] bg-black rounded-lg p-[1.5rem] border border-white/20"
|
||||||
|
>
|
||||||
|
<h3 className="text-white text-2xl font-normal mb-[1rem]">
|
||||||
|
{plan.title}
|
||||||
|
</h3>
|
||||||
|
<div className="mb-[1rem]">
|
||||||
|
<span className="text-white text-[3.375rem] font-bold">
|
||||||
|
${plan.price}
|
||||||
|
</span>
|
||||||
|
<span className="text-white text-xs ml-[0.5rem]">/month</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-white text-[0.875rem] mb-[1rem]">
|
||||||
|
{plan.credits}
|
||||||
|
</p>
|
||||||
|
<button className="w-full bg-white text-black py-[0.75rem] rounded-full mb-[1rem] hover:bg-black hover:text-white transition-colors border border-white/20">
|
||||||
|
{plan.buttonText}
|
||||||
|
</button>
|
||||||
|
<p className="w-full text-center text-white/60 text-[0.75rem] mb-[2rem]">
|
||||||
|
* Billed monthly until cancelled
|
||||||
|
</p>
|
||||||
|
<ul className="space-y-[1rem]">
|
||||||
|
{plan.features.map((feature, featureIndex) => (
|
||||||
|
<li
|
||||||
|
key={featureIndex}
|
||||||
|
className="flex items-center text-white text-[0.875rem]"
|
||||||
|
>
|
||||||
|
<span className="text-[#C73BFF] mr-[0.5rem]">✓</span>
|
||||||
|
{feature}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 额外价格卡片 */}
|
||||||
|
<div className="flex gap-[1.5rem] w-full px-[12rem]">
|
||||||
|
<div className="flex-1 bg-black rounded-lg p-[1.5rem] border border-white/20">
|
||||||
|
<h3 className="text-white text-[1.5rem] font-bold mb-[0.5rem]">
|
||||||
|
Free
|
||||||
|
</h3>
|
||||||
|
<div className="mb-[1rem]">
|
||||||
|
<span className="text-white text-[2.5rem] font-bold">$0</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
|
||||||
|
10 Video mins and 1 AI credit per week, 1 Express avatar, 4 Exports
|
||||||
|
per week with invideo watermark.
|
||||||
|
</p>
|
||||||
|
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
|
||||||
|
No access to generative features.
|
||||||
|
</p>
|
||||||
|
<button className="w-[9rem] bg-[#262626] text-white py-[0.75rem] rounded-full hover:bg-white hover:text-black transition-colors border border-white/20">
|
||||||
|
Try For Free
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 bg-black rounded-lg p-[1.5rem] border border-white/20">
|
||||||
|
<h3 className="text-white text-[1.5rem] font-bold mb-[0.5rem]">
|
||||||
|
Enterprise
|
||||||
|
</h3>
|
||||||
|
<p className="text-white text-[2.5rem] mb-[1rem]">Custom</p>
|
||||||
|
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
|
||||||
|
Custom solutions for large organizations. Advanced security and
|
||||||
|
flexible pricing based on your needs.
|
||||||
|
</p>
|
||||||
|
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
|
||||||
|
on your needs.
|
||||||
|
</p>
|
||||||
|
<button className="w-[9rem] bg-[#262626] text-white py-[0.75rem] rounded-full hover:bg-white hover:text-black transition-colors border border-white/20">
|
||||||
|
Contact Us
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HomeModule6() {
|
||||||
|
return (
|
||||||
|
<div className="home-module6 flex justify-center items-center w-full h-min text-white/50 text-lg bg-black snap-start">
|
||||||
|
© 2025 MovieFlow. All rights reserved.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -102,7 +102,7 @@
|
|||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.5.0",
|
||||||
"styled-components": "^6.1.19",
|
"styled-components": "^6.1.19",
|
||||||
"swiper": "^11.2.8",
|
"swiper": "^11.2.10",
|
||||||
"tailwind-merge": "^2.6.0",
|
"tailwind-merge": "^2.6.0",
|
||||||
"tailwindcss": "3.3.3",
|
"tailwindcss": "3.3.3",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
@ -19470,7 +19470,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/swiper": {
|
"node_modules/swiper": {
|
||||||
"version": "11.2.10",
|
"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==",
|
"integrity": "sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -105,7 +105,7 @@
|
|||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.5.0",
|
||||||
"styled-components": "^6.1.19",
|
"styled-components": "^6.1.19",
|
||||||
"swiper": "^11.2.8",
|
"swiper": "^11.2.10",
|
||||||
"tailwind-merge": "^2.6.0",
|
"tailwind-merge": "^2.6.0",
|
||||||
"tailwindcss": "3.3.3",
|
"tailwindcss": "3.3.3",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
|||||||
BIN
public/assets/1.mp4
Normal file
BIN
public/assets/1.mp4
Normal file
Binary file not shown.
BIN
public/assets/home.mp4
Normal file
BIN
public/assets/home.mp4
Normal file
Binary file not shown.
BIN
public/assets/show (1).mp4
Normal file
BIN
public/assets/show (1).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (10).mp4
Normal file
BIN
public/assets/show (10).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (11).mp4
Normal file
BIN
public/assets/show (11).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (12).mp4
Normal file
BIN
public/assets/show (12).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (13).mp4
Normal file
BIN
public/assets/show (13).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (14).mp4
Normal file
BIN
public/assets/show (14).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (15).mp4
Normal file
BIN
public/assets/show (15).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (2).mp4
Normal file
BIN
public/assets/show (2).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (3).mp4
Normal file
BIN
public/assets/show (3).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (4).mp4
Normal file
BIN
public/assets/show (4).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (5).mp4
Normal file
BIN
public/assets/show (5).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (6).mp4
Normal file
BIN
public/assets/show (6).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (7).mp4
Normal file
BIN
public/assets/show (7).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (8).mp4
Normal file
BIN
public/assets/show (8).mp4
Normal file
Binary file not shown.
BIN
public/assets/show (9).mp4
Normal file
BIN
public/assets/show (9).mp4
Normal file
Binary file not shown.
@ -45,7 +45,6 @@ export function createScreenAdapter(): void {
|
|||||||
// 获取当前窗口尺寸
|
// 获取当前窗口尺寸
|
||||||
const currentWidth = window.innerWidth;
|
const currentWidth = window.innerWidth;
|
||||||
const currentHeight = window.innerHeight;
|
const currentHeight = window.innerHeight;
|
||||||
|
|
||||||
// 计算缩放比例 (1920x1080)
|
// 计算缩放比例 (1920x1080)
|
||||||
const wScale = currentWidth / 1920;
|
const wScale = currentWidth / 1920;
|
||||||
const hScale = currentHeight / 1080;
|
const hScale = currentHeight / 1080;
|
||||||
@ -56,7 +55,10 @@ export function createScreenAdapter(): void {
|
|||||||
console.error("未找到app节点");
|
console.error("未找到app节点");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
(window as any).Scale = {
|
||||||
|
wScale,
|
||||||
|
hScale,
|
||||||
|
};
|
||||||
// 创建样式元素
|
// 创建样式元素
|
||||||
const style = document.createElement("style");
|
const style = document.createElement("style");
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user