diff --git a/README.md b/README.md index 608ffb6..206f780 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,7 @@ bun run api:smoke # API 冒烟测试(需 dev server 已启动) - 持续完善版本 diff 展示 - 完善权限隔离与协作模型 - 优化大文稿下的性能表现 +- ## 参考文档 diff --git a/app/api/users/route.ts b/app/api/users/route.ts new file mode 100644 index 0000000..d626c82 --- /dev/null +++ b/app/api/users/route.ts @@ -0,0 +1,38 @@ +import { z } from "zod"; + +import { apiError, apiOk } from "@/lib/api/response"; +import { createUserRoleOptions } from "@/features/user-create/schema"; + +const createUserPayloadSchema = z.object({ + username: z.string().trim().min(3).max(20), + email: z.string().trim().email(), + role: z.enum(createUserRoleOptions), + password: z.string().min(8), +}); + +export async function POST(request: Request) { + let payload: unknown; + + try { + payload = await request.json(); + } catch { + payload = {}; + } + + const parsed = createUserPayloadSchema.safeParse(payload); + if (!parsed.success) { + return apiError("Invalid payload", "INVALID_PAYLOAD", 400); + } + + return apiOk( + { + user: { + id: crypto.randomUUID(), + username: parsed.data.username, + email: parsed.data.email, + role: parsed.data.role, + }, + }, + 201, + ); +} diff --git a/app/layout.tsx b/app/layout.tsx index c99f7b0..3b74634 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,7 +1,7 @@ import type { Metadata } from "next"; import { ClerkProvider } from "@clerk/nextjs"; import { zhCN } from "@clerk/localizations"; -import { Montserrat, Open_Sans } from "next/font/google"; +import { Montserrat, Open_Sans, Space_Grotesk, Space_Mono } from "next/font/google"; import { QueryProvider } from "@/features/shared/providers/query-provider"; import { Toaster } from "@/components/ui/sonner"; import "./globals.css"; @@ -16,6 +16,17 @@ const openSans = Open_Sans({ subsets: ["latin"], }); +const spaceGrotesk = Space_Grotesk({ + variable: "--font-space-grotesk", + subsets: ["latin"], +}); + +const spaceMono = Space_Mono({ + variable: "--font-space-mono", + subsets: ["latin"], + weight: ["400", "700"], +}); + export const metadata: Metadata = { title: "PPT XML Editor", description: "PPT XML Editor with Clerk authentication", @@ -28,7 +39,10 @@ export default function RootLayout({ }>) { return ( - + {children} diff --git a/app/users/new/page.tsx b/app/users/new/page.tsx new file mode 100644 index 0000000..4e207d9 --- /dev/null +++ b/app/users/new/page.tsx @@ -0,0 +1,19 @@ +import { UserCreateForm } from "@/features/user-create/components/user-create-form"; + +export default function UserCreatePage() { + return ( +
+
+
+ +
+
+ ); +} diff --git a/features/auth/components/auth-shell.tsx b/features/auth/components/auth-shell.tsx index 48fc77c..8c94d2b 100644 --- a/features/auth/components/auth-shell.tsx +++ b/features/auth/components/auth-shell.tsx @@ -18,7 +18,7 @@ export function AuthShell({ title, subtitle, children }: AuthShellProps) {