Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions app/_components/BubbleDiv.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="relative h-[41.77px] w-[226px]">
<span className="typo-16-600 absolute top-1 left-0 z-20 w-full text-center text-black">
현재 <span className="text-bubble-text-highight">775명 </span>
참여중이에요!
<div className="relative" style={{ width: `${w}px`, height: `${h}px` }}>
<span
className={`${typo} absolute left-0 z-20 w-full text-center text-black`}
style={{ top: `${top}px` }}
>
{children || (
<>
현재 <span className="text-bubble-text-highight">775명 </span>
참여중이에요!
</>
)}
</span>
<Image src="/bubble/bubble.svg" alt="bubble" width={226} height={41.77} />
<Image src="/bubble/bubble.svg" alt="말풍선" width={w} height={h} />
</div>
);
};
Expand Down
7 changes: 7 additions & 0 deletions app/_components/LoginActionSection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import BubbleDiv from "@/app/_components/BubbleDiv";
import Button from "@/components/ui/Button";

Check warning on line 3 in app/_components/LoginActionSection.tsx

View workflow job for this annotation

GitHub Actions / lint

'Button' is defined but never used
import { KakaoLoginButton, GoogleLoginButton } from "./SocialButtonList";
import {
Drawer,
Expand All @@ -8,8 +8,14 @@
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer";
import { useRouter } from "next/navigation";

export default function ScreenLoginActionSection() {
const router = useRouter();

const handleEmailLogin = () => {
router.push("/login");
};
const handleKakaoLogin = () => {
// window.location.href = "https://backend.comatching.site/oauth2/authorization/kakao";
alert("코매칭 서비스는 10/13일부로 종료되었습니다.");
Expand Down Expand Up @@ -68,6 +74,7 @@
<button
type="button"
className="all-[unset] cursor-pointer underline"
onClick={handleEmailLogin}
>
이메일로 로그인
</button>
Expand Down
17 changes: 17 additions & 0 deletions app/login/_components/LocalLoginIntro.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";

const LocalLoginIntro = () => {
return (
<section className="mt-6 flex flex-col items-start gap-2">
<span className="typo-26-700 leading-[1.4] text-black">
이메일로
<br /> 코매칭 시작하기
</span>
<span className="typo-16-500 text-color-text-caption2">
로그인하거나 새로운 계정을 만들어보세요.
</span>
</section>
);
};

export default LocalLoginIntro;
87 changes: 87 additions & 0 deletions app/login/_components/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client";
import BubbleDiv from "@/app/_components/BubbleDiv";
import Button from "@/components/ui/Button";
import { User } from "lucide-react";
import React, { useState } from "react";

export const LoginForm = () => {
// TODO: 로그인 실패 로직 연동 필요
const [isWrong, setIsWrong] = useState(false);

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]";
return (
<section className="mt-10 flex w-full flex-1 flex-col items-start gap-6">
<form
className="flex w-full flex-col gap-4"
onSubmit={(e) => {
e.preventDefault();
// 테스트를 위해 submit시 에러 토글 (나중에 실제 로직으로 교체)
setIsWrong(true);
}}
>
<div className="flex w-full flex-col gap-2">
<label htmlFor="email" className="typo-14-500 text-gray-700">
아이디(이메일)
</label>
<input
id="email"
type="email"
name="email"
placeholder="이메일 입력"
required
autoComplete="email"
className={INPUT_CLASSNAME}
style={INPUT_STYLE}
/>
</div>

<div className="relative mb-6 flex w-full flex-col gap-2">
<label htmlFor="password" className="typo-14-500 text-gray-700">
비밀번호
</label>
<input
id="password"
type="password"
name="password"
placeholder="비밀번호 입력"
required
autoComplete="current-password"
className={INPUT_CLASSNAME}
style={INPUT_STYLE}
/>
{isWrong && (
<span className="typo-12-400 text-color-flame-700 absolute bottom-[-25px] left-0">
* 이메일 혹은 비밀번호가 틀립니다
</span>
)}
</div>
<Button shadow={true} type="submit">
로그인
</Button>
</form>
<div className="typo-14-500 text-color-text-caption2 flex w-full justify-center">
<button type="button">이메일 찾기</button>
<span className="mx-4">|</span>
<button type="button">비밀번호 변경</button>
</div>

<div className="mt-auto flex w-full flex-col items-center gap-4">
<BubbleDiv w={162} h={26} typo="typo-12-600" top={3}>
아직 계정이 없으신가요?!
</BubbleDiv>
<button
type="button"
className="typo-14-500 flex items-center gap-1 border-b-2 border-gray-500 text-gray-500"
>
<User />
이메일로 회원가입
</button>
</div>
</section>
);
};
16 changes: 16 additions & 0 deletions app/login/_components/ScreenLocalLoginPage.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<main className="flex h-dvh flex-col items-start px-4 pt-2 pb-[6.2vh]">
<BackButton />
<LocalLoginIntro />
<LoginForm />
</main>
);
};

export default ScreenLocalLoginPage;
14 changes: 14 additions & 0 deletions app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -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 <ScreenLocalLoginPage />;
};

export default LoginPage;
35 changes: 35 additions & 0 deletions components/ui/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"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 (
<button
type="button"
onClick={handleClick}
className={cn(
"flex h-12 w-12 cursor-pointer items-center justify-center rounded-full border border-[#FFFFFF]/30 bg-[#FFFFFF]/50 [box-shadow:0px_4px_8px_rgba(0,0,0,0.08),0px_0px_16px_rgba(0,0,0,0.1)] backdrop-blur-[15px]",
positionClass,
className,
)}
>
<ChevronLeft className="text-[#282828]" size={20} />
</button>
);
};
2 changes: 1 addition & 1 deletion components/ui/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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가 덮어씌워짐)
Expand Down
Loading