76 lines
3.4 KiB
TypeScript
76 lines
3.4 KiB
TypeScript
import { redirect } from "next/navigation";
|
|
import { and, desc, eq } from "drizzle-orm";
|
|
import { auth } from "@/app/(auth)/auth";
|
|
import { VideoCanvasHome, type VideoCanvasHomeProject } from "@/components/canvas/VideoCanvasHome";
|
|
import { db } from "@/lib/db";
|
|
import { getSiteSettings } from "@/lib/db/queries";
|
|
import { canvasProject } from "@/lib/db/schema";
|
|
|
|
type Props = { searchParams?: Promise<Record<string, string | string[] | undefined>> };
|
|
|
|
function first(value: string | string[] | undefined) {
|
|
return Array.isArray(value) ? value[0] : value;
|
|
}
|
|
|
|
function canvasHref(id: string, incoming: Record<string, string | string[] | undefined>) {
|
|
const params = new URLSearchParams({ mode: "video", workspaceType: "video" });
|
|
for (const [key, value] of Object.entries(incoming)) {
|
|
if (["new", "mode", "workspaceType"].includes(key) || value === undefined) continue;
|
|
for (const item of Array.isArray(value) ? value : [value]) params.append(key, item);
|
|
}
|
|
return `/canvas/${id}?${params.toString()}`;
|
|
}
|
|
|
|
function projectPreview(thumbnail: string | null, canvasData: unknown) {
|
|
const nodes = canvasData && typeof canvasData === "object" && "nodes" in canvasData
|
|
? (canvasData as { nodes?: unknown }).nodes : null;
|
|
const candidates = [thumbnail];
|
|
if (Array.isArray(nodes)) for (const node of [...nodes].reverse()) {
|
|
if (!node || typeof node !== "object") continue;
|
|
const item = node as { inputType?: string; draftValues?: Record<string, unknown> };
|
|
const draft = item.draftValues || {};
|
|
candidates.push(
|
|
String(draft.poster || draft.previewImageUrl || draft.thumbnailUrl || draft.resultImage || (item.inputType === "image" ? draft.mediaUrl || (Array.isArray(draft.url) ? draft.url[0] : "") : "") || ""),
|
|
);
|
|
}
|
|
return candidates.find(value => typeof value === "string" && (value.startsWith("https://") || value.startsWith("/"))) || null;
|
|
}
|
|
|
|
export default async function VideoCanvasHomePage({ searchParams }: Props) {
|
|
const session = await auth();
|
|
if (!session?.user?.id) redirect("/login?callbackUrl=%2Fvideo-canvas");
|
|
|
|
const params = (await searchParams) || {};
|
|
if (first(params.new) === "1") {
|
|
const [created] = await db.insert(canvasProject).values({
|
|
userId: session.user.id,
|
|
title: "未命名视频画布",
|
|
workspaceType: "video",
|
|
canvasData: { nodes: [], edges: [], viewport: { x: 0, y: 0, zoom: 1 } },
|
|
}).returning({ id: canvasProject.id });
|
|
redirect(canvasHref(created.id, params));
|
|
}
|
|
|
|
const [rows, siteSettings] = await Promise.all([db.select({
|
|
id: canvasProject.id,
|
|
title: canvasProject.title,
|
|
thumbnail: canvasProject.thumbnail,
|
|
canvasData: canvasProject.canvasData,
|
|
createdAt: canvasProject.createdAt,
|
|
updatedAt: canvasProject.updatedAt,
|
|
}).from(canvasProject).where(and(
|
|
eq(canvasProject.userId, session.user.id),
|
|
eq(canvasProject.workspaceType, "video"),
|
|
)).orderBy(desc(canvasProject.updatedAt)).limit(25), getSiteSettings()]);
|
|
|
|
const projects: VideoCanvasHomeProject[] = rows.slice(0, 24).map(row => ({
|
|
id: row.id,
|
|
title: row.title,
|
|
thumbnail: projectPreview(row.thumbnail, row.canvasData),
|
|
createdAt: row.createdAt.toISOString(),
|
|
updatedAt: row.updatedAt.toISOString(),
|
|
}));
|
|
|
|
return <VideoCanvasHome initialHasMore={rows.length > 24} initialProjects={projects} siteLogo={siteSettings.siteLogo} siteLogoDark={siteSettings.siteLogoDark} siteName={siteSettings.siteName} userName={session.user.name || ""} />;
|
|
}
|