From 3ac11189a3583d5550e3b421b68dc65673f8fbbd Mon Sep 17 00:00:00 2001 From: zhangwei <775925302@qq.com> Date: Fri, 19 Sep 2025 00:32:10 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A4=84=E7=90=86=E4=BA=86=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E9=93=BE=E6=8E=A5=E5=92=8C=E5=8F=82=E6=95=B0=E4=BF=9D?= =?UTF-8?q?=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/app/editor/page.tsx | 66 +++++++++++++++++ apps/web/src/app/landing/page.tsx | 23 ++++++ apps/web/src/app/page.tsx | 42 ++++++----- apps/web/src/app/projects/page.tsx | 113 ++++++++++++++++++++++------- apps/web/src/components/header.tsx | 13 +++- 5 files changed, 207 insertions(+), 50 deletions(-) create mode 100644 apps/web/src/app/editor/page.tsx create mode 100644 apps/web/src/app/landing/page.tsx diff --git a/apps/web/src/app/editor/page.tsx b/apps/web/src/app/editor/page.tsx new file mode 100644 index 000000000..49fbded88 --- /dev/null +++ b/apps/web/src/app/editor/page.tsx @@ -0,0 +1,66 @@ +"use client"; + +import { useProjectStore } from "@/stores/project-store"; +import { Loader2 } from "lucide-react"; +import { useRouter, useSearchParams } from "next/navigation"; +import { Suspense, useEffect } from "react"; + +function EditorIndexContent() { + const { createNewProject } = useProjectStore(); + const router = useRouter(); + const searchParams = useSearchParams(); + + useEffect(() => { + const createAndRedirect = async () => { + try { + // 创建新项目 + const projectId = await createNewProject("新项目"); + + // 保留查询参数 + const queryString = searchParams.toString(); + const redirectUrl = queryString + ? `/editor/${projectId}?${queryString}` + : `/editor/${projectId}`; + + // 重定向到编辑器页面 + router.replace(redirectUrl); + } catch (error) { + console.error("创建项目失败:", error); + // 如果创建失败,重定向到项目列表页 + const queryString = searchParams.toString(); + const fallbackUrl = queryString + ? `/projects?${queryString}` + : "/projects"; + router.replace(fallbackUrl); + } + }; + + createAndRedirect(); + }, [createNewProject, router, searchParams]); + + return ( +
+
+ +

正在创建新项目...

+
+
+ ); +} + +export default function EditorIndex() { + return ( + +
+ +

正在加载...

+
+ + } + > + +
+ ); +} diff --git a/apps/web/src/app/landing/page.tsx b/apps/web/src/app/landing/page.tsx new file mode 100644 index 000000000..3f501a56b --- /dev/null +++ b/apps/web/src/app/landing/page.tsx @@ -0,0 +1,23 @@ +import { Footer } from "@/components/footer"; +import { Header } from "@/components/header"; +import { Hero } from "@/components/landing/hero"; +import { SITE_URL } from "@/constants/site"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "OpenCut - 免费开源视频编辑器", + description: "一个免费、开源的网页、桌面和移动端视频编辑器。保护隐私,功能完整,无水印。", + alternates: { + canonical: `${SITE_URL}/landing`, + }, +}; + +export default async function LandingPage() { + return ( +
+
+ +
+ ); +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 818884ed0..403c24c1e 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,21 +1,27 @@ -import { Hero } from "@/components/landing/hero"; -import { Header } from "@/components/header"; -import { Footer } from "@/components/footer"; -import type { Metadata } from "next"; -import { SITE_URL } from "@/constants/site"; +import { redirect } from "next/navigation"; -export const metadata: Metadata = { - alternates: { - canonical: SITE_URL, - }, -}; +interface HomeProps { + searchParams: { [key: string]: string | string[] | undefined }; +} -export default async function Home() { - return ( -
-
- -
- ); +export default async function Home({ searchParams }: HomeProps) { + // 构建查询字符串 + const queryString = new URLSearchParams(); + + for (const [key, value] of Object.entries(searchParams)) { + if (value !== undefined) { + if (Array.isArray(value)) { + for (const v of value) { + queryString.append(key, v); + } + } else { + queryString.set(key, value); + } + } + } + + const queryStr = queryString.toString(); + const redirectUrl = queryStr ? `/editor?${queryStr}` : "/editor"; + + redirect(redirectUrl); } diff --git a/apps/web/src/app/projects/page.tsx b/apps/web/src/app/projects/page.tsx index 3d66a3c56..30af961eb 100644 --- a/apps/web/src/app/projects/page.tsx +++ b/apps/web/src/app/projects/page.tsx @@ -1,46 +1,46 @@ "use client"; -import { - Calendar, - ChevronLeft, - Loader2, - MoreHorizontal, - ArrowDown01, - Plus, - Search, - Trash2, - Video, - X, -} from "lucide-react"; -import Image from "next/image"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useCallback, useEffect, useState } from "react"; import { DeleteProjectDialog } from "@/components/delete-project-dialog"; import { RenameProjectDialog } from "@/components/rename-project-dialog"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Checkbox } from "@/components/ui/checkbox"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; +import { Skeleton } from "@/components/ui/skeleton"; import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, } from "@/components/ui/tooltip"; -import { Skeleton } from "@/components/ui/skeleton"; import { useProjectStore } from "@/stores/project-store"; import { useTimelineStore } from "@/stores/timeline-store"; import type { TProject } from "@/types/project"; +import { + ArrowDown01, + Calendar, + ChevronLeft, + Loader2, + MoreHorizontal, + Plus, + Search, + Trash2, + Video, + X, +} from "lucide-react"; +import Image from "next/image"; +import Link from "next/link"; +import { useRouter, useSearchParams } from "next/navigation"; +import { Suspense, useCallback, useEffect, useState } from "react"; -export default function ProjectsPage() { +function ProjectsPageContent() { const { savedProjects, isLoading, @@ -63,6 +63,7 @@ export default function ProjectsPage() { const [searchQuery, setSearchQuery] = useState(""); const [sortOption, setSortOption] = useState("createdAt-desc"); const router = useRouter(); + const searchParams = useSearchParams(); const getProjectThumbnail = useCallback( async (projectId: string): Promise => { @@ -92,7 +93,14 @@ export default function ProjectsPage() { const handleCreateProject = async () => { const projectId = await createNewProject("New Project"); console.log("projectId", projectId); - router.push(`/editor/${projectId}`); + + // 保留查询参数 + const queryString = searchParams.toString(); + const redirectUrl = queryString + ? `/editor/${projectId}?${queryString}` + : `/editor/${projectId}`; + + router.push(redirectUrl); }; const handleSelectProject = (projectId: string, checked: boolean) => { @@ -644,3 +652,52 @@ function NoResults({ ); } + +export default function ProjectsPage() { + return ( + +
+ + + Back + +
+
+
+
+

+ Your Projects +

+

Loading...

+
+
+
+ {Array.from({ length: 8 }, (_, index) => ( +
+ +
+ +
+ + +
+
+
+ ))} +
+
+ + } + > + +
+ ); +} diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index f8877330d..d779ffd4e 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -1,15 +1,15 @@ "use client"; -import Link from "next/link"; -import { Button } from "./ui/button"; import { ArrowRight } from "lucide-react"; -import { HeaderBase } from "./header-base"; import Image from "next/image"; +import Link from "next/link"; +import { HeaderBase } from "./header-base"; import { ThemeToggle } from "./theme-toggle"; +import { Button } from "./ui/button"; export function Header() { const leftContent = ( - + OpenCut Logo
+ + +