diff --git a/app/(root)/page.tsx b/app/(root)/page.tsx
index 6b484a3..ff0c27b 100644
--- a/app/(root)/page.tsx
+++ b/app/(root)/page.tsx
@@ -1,14 +1,17 @@
import BookCard from "@/components/BookCard";
import HeroSection from "@/components/HeroSection";
-import { sampleBooks } from "@/lib/constants";
+import { getAllBooks } from "@/lib/actions/book.actions";
+
+export default async function Page() {
+ const bookResult = await getAllBooks();
+ const books = bookResult.success ? bookResult.data ?? [] : [];
-export default function Page() {
return (
-
+
- {sampleBooks.map((book) => (
+ {books.map((book) => (
))}
-
+
);
}
diff --git a/app/api/upload/route.ts b/app/api/upload/route.ts
new file mode 100644
index 0000000..bcbfb14
--- /dev/null
+++ b/app/api/upload/route.ts
@@ -0,0 +1,52 @@
+import { MAX_FILE_SIZE } from "@/lib/constants";
+import { auth } from "@clerk/nextjs/server";
+import { handleUpload, HandleUploadBody } from "@vercel/blob/client";
+import { NextRequest, NextResponse } from "next/server";
+
+export async function POST(request: NextRequest): Promise {
+ const body = (await request.json()) as HandleUploadBody;
+
+ try {
+ // 处理上传请求
+ const jsonResponse = await handleUpload({
+ token: process.env.BLOB_READ_WRITE_TOKEN,
+ body,
+ request,
+ // 在生成上传令牌之前执行的函数
+ onBeforeGenerateToken: async () => {
+ // 检查用户是否登录
+ const { userId } = await auth();
+ if (!userId) {
+ throw new Error("Unauthorized: 用户未登录");
+ }
+
+ return {
+ allowedContentTypes: [
+ "application/pdf",
+ "image/jpeg",
+ "image/png",
+ "image/webp",
+ ],
+ addRandomSuffix: true,
+ maximumSizeInBytes: MAX_FILE_SIZE,
+ tokenPayload: JSON.stringify({ userId }),
+ };
+ },
+ // 上传完成后的回调
+ onUploadCompleted: async ({ blob, tokenPayload }) => {
+ console.log("文件已上传至 Blob", blob.url);
+
+ const payload = tokenPayload ? JSON.parse(tokenPayload) : null;
+ const userId = payload?.userId;
+
+ // TODO: 上报PostHog
+ },
+ });
+
+ return NextResponse.json(jsonResponse);
+ } catch (e) {
+ const message = e instanceof Error ? e.message : "未知错误";
+ const status = message.includes("Unauthorized") ? 401 : 500;
+ return NextResponse.json({ error: message }, { status });
+ }
+}
diff --git a/app/layout.tsx b/app/layout.tsx
index bc83904..b8b4682 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -4,7 +4,7 @@ import { ClerkProvider } from "@clerk/nextjs";
import "./globals.css";
import NavBar from "@/components/NavBar";
import { CLERK_AUTH_APPEARANCE_OVERRIDE } from "@/lib/constants";
-
+import { Toaster } from "@/components/ui/sonner"
const ibmPlexSerif = IBM_Plex_Serif({
variable: "--font-ibm-plex-serif",
@@ -40,6 +40,7 @@ export default function RootLayout({
{children}
+