diff --git a/app/_components/BubbleDiv.tsx b/app/_components/BubbleDiv.tsx
index 38f1d87..856af87 100644
--- a/app/_components/BubbleDiv.tsx
+++ b/app/_components/BubbleDiv.tsx
@@ -1,14 +1,33 @@
import Image from "next/image";
import React from "react";
-const BubbleDiv = () => {
+const BubbleDiv = ({
+ children,
+ w = 226,
+ h = 41.77,
+ typo = "typo-16-600",
+ top = 1,
+}: {
+ children?: React.ReactNode;
+ w?: number;
+ h?: number;
+ typo?: string;
+ top?: number;
+}) => {
return (
-
-
- 현재 775명
- 참여중이에요!
+
+
+ {children || (
+ <>
+ 현재 775명
+ 참여중이에요!
+ >
+ )}
-
+
);
};
diff --git a/app/_components/LoginActionSection.tsx b/app/_components/LoginActionSection.tsx
index d18909e..27b061b 100644
--- a/app/_components/LoginActionSection.tsx
+++ b/app/_components/LoginActionSection.tsx
@@ -1,6 +1,5 @@
"use client";
import BubbleDiv from "@/app/_components/BubbleDiv";
-import Button from "@/components/ui/Button";
import { KakaoLoginButton, GoogleLoginButton } from "./SocialButtonList";
import {
Drawer,
@@ -8,6 +7,7 @@ import {
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer";
+import Link from "next/link";
export default function ScreenLoginActionSection() {
const handleKakaoLogin = () => {
@@ -65,12 +65,12 @@ export default function ScreenLoginActionSection() {
혹은
-
+
diff --git a/app/login/_components/LocalLoginIntro.tsx b/app/login/_components/LocalLoginIntro.tsx
new file mode 100644
index 0000000..6e93978
--- /dev/null
+++ b/app/login/_components/LocalLoginIntro.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+
+const LocalLoginIntro = () => {
+ return (
+
+
+ 이메일로
+
코매칭 시작하기
+
+
+ 로그인하거나 새로운 계정을 만들어보세요.
+
+
+ );
+};
+
+export default LocalLoginIntro;
diff --git a/app/login/_components/LoginForm.tsx b/app/login/_components/LoginForm.tsx
new file mode 100644
index 0000000..2d97e91
--- /dev/null
+++ b/app/login/_components/LoginForm.tsx
@@ -0,0 +1,90 @@
+"use client";
+import BubbleDiv from "@/app/_components/BubbleDiv";
+import Button from "@/components/ui/Button";
+import { User } from "lucide-react";
+import React, { useActionState } from "react";
+import Link from "next/link";
+import { loginAction } from "@/lib/actions/loginAction";
+
+const INPUT_STYLE = {
+ background:
+ "linear-gradient(180deg, rgba(248, 248, 248, 0.03) 0%, rgba(248, 248, 248, 0.24) 100%)",
+};
+const INPUT_CLASSNAME =
+ "all:unset box-border w-full border-b border-gray-300 px-2 py-[14.5px] leading-[19px] placeholder:text-[#B3B3B3]";
+
+export const LoginForm = () => {
+ // React 19: useActionState로 폼 상태 및 팬딩 처리 관리
+ const [state, formAction, isPending] = useActionState(loginAction, {
+ success: false,
+ message: "",
+ });
+
+ return (
+
+
+
+
+ 이메일 찾기
+
+ |
+
+ 비밀번호 변경
+
+
+
+
+
+ 아직 계정이 없으신가요?!
+
+
+
+
+ );
+};
diff --git a/app/login/_components/ScreenLocalLoginPage.tsx b/app/login/_components/ScreenLocalLoginPage.tsx
new file mode 100644
index 0000000..f5d5a9f
--- /dev/null
+++ b/app/login/_components/ScreenLocalLoginPage.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+import { BackButton } from "@/components/ui/BackButton";
+import LocalLoginIntro from "./LocalLoginIntro";
+import { LoginForm } from "./LoginForm";
+
+const ScreenLocalLoginPage = () => {
+ return (
+
+
+
+
+
+ );
+};
+
+export default ScreenLocalLoginPage;
diff --git a/app/login/page.tsx b/app/login/page.tsx
new file mode 100644
index 0000000..5821d39
--- /dev/null
+++ b/app/login/page.tsx
@@ -0,0 +1,14 @@
+import React from "react";
+import { Metadata } from "next";
+import ScreenLocalLoginPage from "./_components/ScreenLocalLoginPage";
+
+export const metadata: Metadata = {
+ title: "로그인 | COMAtching",
+ description: "COMAtching 로그인 페이지",
+};
+
+const LoginPage = () => {
+ return ;
+};
+
+export default LoginPage;
diff --git a/components/ui/BackButton.tsx b/components/ui/BackButton.tsx
new file mode 100644
index 0000000..6ab4b30
--- /dev/null
+++ b/components/ui/BackButton.tsx
@@ -0,0 +1,36 @@
+"use client";
+import React from "react";
+import { useRouter } from "next/navigation";
+import { ChevronLeft } from "lucide-react";
+import { cn } from "@/lib/utils";
+
+type BackButtonProps = {
+ variant?: "absolute" | "static";
+ className?: string;
+ onClick?: () => void;
+};
+
+export const BackButton = ({
+ variant = "static",
+ className = "",
+ onClick,
+}: BackButtonProps) => {
+ const router = useRouter();
+ const positionClass = variant === "absolute" ? "absolute left-4 top-2" : "";
+ const handleClick = onClick ?? (() => router.back());
+
+ return (
+
+ );
+};
diff --git a/components/ui/Button.tsx b/components/ui/Button.tsx
index a0f4dda..a741f05 100644
--- a/components/ui/Button.tsx
+++ b/components/ui/Button.tsx
@@ -48,7 +48,7 @@ export default function Button({
disabled={disabled}
className={cn(
// 기본 스타일 (기본 높이 h-12, 너비 w-full, 폰트 등 복구)
- "typo-20-600 text-button-primary-text-default flex h-12 w-full items-center justify-center rounded-[12px] transition-colors duration-100",
+ "typo-20-600 text-button-primary-text-default bg-button-primary flex h-12 w-full items-center justify-center rounded-[16px] transition-colors duration-100",
fixed && "fixed z-50 mx-auto",
disabled ? "cursor-not-allowed" : "cursor-pointer",
// 1. 사용자 className 먼저 적용 (여기서 h-10 등을 넣으면 위 h-12가 덮어씌워짐)
diff --git a/lib/actions/loginAction.ts b/lib/actions/loginAction.ts
new file mode 100644
index 0000000..5260d69
--- /dev/null
+++ b/lib/actions/loginAction.ts
@@ -0,0 +1,31 @@
+"use server";
+
+type LoginState = {
+ success: boolean;
+ message: string;
+};
+
+export async function loginAction(
+ prevState: LoginState,
+ formData: FormData,
+): Promise {
+ const email = formData.get("email");
+ const password = formData.get("password");
+
+ // Mock delay
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+
+ // TODO: 실제 백엔드 API 호출로 교체 필요
+ // const response = await fetch("https://api.comatching.com/login", {
+ // method: "POST",
+ // body: JSON.stringify({ email, password }),
+ // headers: { "Content-Type": "application/json" },
+ // });
+
+ // Mock logic
+ if (email === "test@test.com" && password === "1234") {
+ return { success: true, message: "" };
+ }
+
+ return { success: false, message: "이메일 혹은 비밀번호가 틀립니다" };
+}