From 4a321634bebff2ae77b413eeaf98f0c7314fd773 Mon Sep 17 00:00:00 2001 From: HyunseokLEE Date: Fri, 14 Nov 2025 16:51:58 +0900 Subject: [PATCH 01/12] =?UTF-8?q?CDP-210=20feat=E2=9C=A8=20(signup):=20sig?= =?UTF-8?q?nup=20group=20button=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20s?= =?UTF-8?q?ignup=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EC=A1=B0?= =?UTF-8?q?=EB=A6=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/signup/page.tsx | 6 ++ .../auth/signup/SignupGroupButton.tsx | 93 +++++++++++++------ src/lib/constants.ts | 29 ------ 3 files changed, 72 insertions(+), 56 deletions(-) diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx index 575ca43..f1a0785 100644 --- a/src/app/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -1,4 +1,6 @@ import { AuthHeader } from "@/components/auth/AuthHeader"; +import { AuthMain } from "@/components/auth/AuthMain"; +import { SignupGroupButton } from "@/components/auth/signup/SignupGroupButton"; import { SignupPageTitle } from "@/components/auth/signup/SignupPageTitle"; import { SignupSubtitle } from "@/components/auth/signup/SignupSubTitle"; import { makePageMetadata } from "@/seo/metadata"; @@ -19,6 +21,10 @@ export default function SignupPage() { + + + + ); } diff --git a/src/components/auth/signup/SignupGroupButton.tsx b/src/components/auth/signup/SignupGroupButton.tsx index bdb4b1b..c372d59 100644 --- a/src/components/auth/signup/SignupGroupButton.tsx +++ b/src/components/auth/signup/SignupGroupButton.tsx @@ -1,45 +1,84 @@ "use client"; -import { SIGNUP_BTNS } from "@/lib/constants"; +import { useFadeSlideInOnMount } from "@/hooks/useMotionPresets"; import { cn } from "@/lib/utils"; import { Button } from "@/shared/button"; import { Icon } from "@/shared/Icon"; import Image from "next/image"; +import Link from "next/link"; import * as React from "react"; -interface Props { +interface SignupGroupButtonProps { className?: string; } -export const SignupGroupButton = React.forwardRef(({ className }, ref) => { - return ( -
- {SIGNUP_BTNS.map(({ key, bg, label, icon }) => ( +export const SignupGroupButton = React.forwardRef( + ({ className }, ref) => { + const fadeClass = useFadeSlideInOnMount("up"); + + return ( +
+ {/* 1) 일반 회원가입 → 이메일 회원가입 폼 페이지로 이동 */} + + + + + {/* 2) Google로 가입 */} + + {/* 3) 카카오로 가입 */} + - ))} -
- ); -}); +
+ ); + }, +); + SignupGroupButton.displayName = "SignupGroupButton"; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index bb6689d..15e7bba 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -27,35 +27,6 @@ export const OG_DEFAULT_IMAGE = "/og/og-default.png"; /** 언어 / 지역 설정 */ export const LOCALE = "ko_KR"; -/* ------------------------------------------------- - 🪪 회원가입 버튼 목록 (Signup Buttons) - - SignupGroupButton에서 사용 - - bg: cva variant key와 1:1 매핑 - ------------------------------------------------- */ - -export const SIGNUP_BTNS = [ - { - key: "email", - bg: "basic" as const, - label: "일반 회원가입", - icon: { kind: "lucide" as const, name: "user-plus2" as const, size: 28 }, // 28px ≒ w-7 h-7 - }, - { - key: "google", - bg: "google" as const, - label: "Google로 가입", - icon: { kind: "image" as const, src: "/icons/google.svg", width: 36, height: 36 }, - }, - { - key: "kakao", - bg: "kakao" as const, - label: "카카오로 가입", - icon: { kind: "image" as const, src: "/icons/kakaotalk.svg", width: 36, height: 36 }, - }, -] as const; - -export type SignupButtonKey = (typeof SIGNUP_BTNS)[number]["key"]; - /* ------------------------------------------------- 🧩 Layout - Footer - LandingFooter에서 사용 From 5a4cc57705ce1fefd2e4d68f3e81b5a09b6aa443 Mon Sep 17 00:00:00 2001 From: HyunseokLEE Date: Sun, 16 Nov 2025 01:09:00 +0900 Subject: [PATCH 02/12] =?UTF-8?q?CDP-206=20refactor=F0=9F=94=A8=20(title):?= =?UTF-8?q?=20title=20=EA=B3=B5=ED=86=B5=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/login/page.tsx | 7 +++---- src/app/(auth)/signup/page.tsx | 7 +++---- src/components/auth/AuthTitle.tsx | 13 +++++++++++++ src/components/auth/login/LoginPageTitle.tsx | 7 ------- src/components/auth/login/LoginSubtitle.tsx | 3 --- src/components/auth/signup/SignupPageTitle.tsx | 7 ------- src/components/auth/signup/SignupSubTitle.tsx | 3 --- 7 files changed, 19 insertions(+), 28 deletions(-) create mode 100644 src/components/auth/AuthTitle.tsx delete mode 100644 src/components/auth/login/LoginPageTitle.tsx delete mode 100644 src/components/auth/login/LoginSubtitle.tsx delete mode 100644 src/components/auth/signup/SignupPageTitle.tsx delete mode 100644 src/components/auth/signup/SignupSubTitle.tsx diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index 092a607..d35451f 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,8 +1,7 @@ import { AuthHeader } from "@/components/auth/AuthHeader"; import { AuthMain } from "@/components/auth/AuthMain"; +import { SubTitle, Title } from "@/components/auth/AuthTitle"; import { LoginForm } from "@/components/auth/login/LoginForm"; -import { LoginPageTitle } from "@/components/auth/login/LoginPageTitle"; -import { LoginSubtitle } from "@/components/auth/login/LoginSubtitle"; import { makePageMetadata } from "@/seo/metadata"; export const metadata = { @@ -18,8 +17,8 @@ export default function LoginPage() { return ( <> - - + 로그인 + 오늘도 만나서 반가워요! diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx index f1a0785..229f6bf 100644 --- a/src/app/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -1,8 +1,7 @@ import { AuthHeader } from "@/components/auth/AuthHeader"; import { AuthMain } from "@/components/auth/AuthMain"; +import { SubTitle, Title } from "@/components/auth/AuthTitle"; import { SignupGroupButton } from "@/components/auth/signup/SignupGroupButton"; -import { SignupPageTitle } from "@/components/auth/signup/SignupPageTitle"; -import { SignupSubtitle } from "@/components/auth/signup/SignupSubTitle"; import { makePageMetadata } from "@/seo/metadata"; export const metadata = { @@ -18,8 +17,8 @@ export default function SignupPage() { return ( <> - - + 회원가입 + 원하시는 가입 방식을 선택해주세요. diff --git a/src/components/auth/AuthTitle.tsx b/src/components/auth/AuthTitle.tsx new file mode 100644 index 0000000..04d9b4f --- /dev/null +++ b/src/components/auth/AuthTitle.tsx @@ -0,0 +1,13 @@ +import type { AuthCommonProps } from "@/types/auth"; + +export function Title({ children }: AuthCommonProps) { + return ( +

+ {children} +

+ ); +} + +export function SubTitle({ children }: AuthCommonProps) { + return

{children}

; +} diff --git a/src/components/auth/login/LoginPageTitle.tsx b/src/components/auth/login/LoginPageTitle.tsx deleted file mode 100644 index 67c3393..0000000 --- a/src/components/auth/login/LoginPageTitle.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export function LoginPageTitle() { - return ( -

- 로그인 -

- ); -} diff --git a/src/components/auth/login/LoginSubtitle.tsx b/src/components/auth/login/LoginSubtitle.tsx deleted file mode 100644 index 4ef609e..0000000 --- a/src/components/auth/login/LoginSubtitle.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export function LoginSubtitle() { - return

오늘도 만나서 반가워요!

; -} diff --git a/src/components/auth/signup/SignupPageTitle.tsx b/src/components/auth/signup/SignupPageTitle.tsx deleted file mode 100644 index 6e84dc0..0000000 --- a/src/components/auth/signup/SignupPageTitle.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export function SignupPageTitle() { - return ( -

- 회원가입 -

- ); -} diff --git a/src/components/auth/signup/SignupSubTitle.tsx b/src/components/auth/signup/SignupSubTitle.tsx deleted file mode 100644 index 2263fef..0000000 --- a/src/components/auth/signup/SignupSubTitle.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export function SignupSubtitle() { - return

원하시는 가입 방식을 선택해주세요.

; -} From f21854ae035569ab5706d8ffb8967847f5a52904 Mon Sep 17 00:00:00 2001 From: HyunseokLEE Date: Sun, 16 Nov 2025 01:10:50 +0900 Subject: [PATCH 03/12] =?UTF-8?q?CDP-206=20refactor=F0=9F=94=A8=20(type):?= =?UTF-8?q?=20state=20type=20auth=20=ED=8C=8C=EC=9D=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stores/authForm.store.ts | 2 +- src/types/auth.ts | 41 ++++++++++++++++++++++++++++++++++++ src/types/authForm.ts | 17 --------------- 3 files changed, 42 insertions(+), 18 deletions(-) delete mode 100644 src/types/authForm.ts diff --git a/src/stores/authForm.store.ts b/src/stores/authForm.store.ts index b0783c6..008d989 100644 --- a/src/stores/authForm.store.ts +++ b/src/stores/authForm.store.ts @@ -1,4 +1,4 @@ -import type { AuthFormState } from "@/types/authForm"; +import type { AuthFormState } from "@/types/auth"; import { create } from "zustand"; export const useAuthFormStore = create((set, get) => ({ diff --git a/src/types/auth.ts b/src/types/auth.ts index 8afa326..0a28cdc 100644 --- a/src/types/auth.ts +++ b/src/types/auth.ts @@ -3,3 +3,44 @@ import type { ReactNode } from "react"; export interface AuthCommonProps { children: ReactNode; } + +export interface AuthFormState { + email: string; + password: string; + emailError: boolean; + passwordError: boolean; + isPasswordVisible: boolean; + + setEmail: (value: string) => void; + setPassword: (value: string) => void; + + clearEmailError: () => void; + clearPasswordError: () => void; + + togglePasswordVisible: () => void; + + validateLogin: () => boolean; +} + +export interface SignupFormProps { + className?: string; + /** 인풋 id / name */ + fieldId: string; + fieldName: string; + /** 라벨 텍스트 (예: 이름, 이메일) */ + label: string; + /** 인풋 타입 */ + type?: "text" | "email" | "password"; + /** placeholder */ + placeholder?: string; + /** autoComplete 힌트 */ + autoComplete?: string; + /** 다음 버튼 라벨 (기본: "다음") */ + nextLabel?: string; + /** 이전 버튼 표시 여부 */ + showPrev?: boolean; + /** 다음 클릭(폼 submit) 콜백 */ + onNext: () => void; + /** 이전 클릭 콜백 (showPrev=true일 때만 사용) */ + onPrev?: () => void; +} diff --git a/src/types/authForm.ts b/src/types/authForm.ts deleted file mode 100644 index 6593a65..0000000 --- a/src/types/authForm.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface AuthFormState { - email: string; - password: string; - emailError: boolean; - passwordError: boolean; - isPasswordVisible: boolean; - - setEmail: (value: string) => void; - setPassword: (value: string) => void; - - clearEmailError: () => void; - clearPasswordError: () => void; - - togglePasswordVisible: () => void; - - validateLogin: () => boolean; -} From c4ee8053689d74de167c89b90a337a4919943ff0 Mon Sep 17 00:00:00 2001 From: HyunseokLEE Date: Sun, 16 Nov 2025 01:11:27 +0900 Subject: [PATCH 04/12] =?UTF-8?q?CDP-206=20refactor=F0=9F=94=A8=20(button)?= =?UTF-8?q?:=20auth=20=EB=B2=84=ED=8A=BC=20white=20=EC=83=89=EA=B9=94=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/variants/button.auth.ts | 1 + src/types/button.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/variants/button.auth.ts b/src/lib/variants/button.auth.ts index 03a3450..8a2f734 100644 --- a/src/lib/variants/button.auth.ts +++ b/src/lib/variants/button.auth.ts @@ -36,6 +36,7 @@ export const loginButtonVariants = cva( "border-0", "hover:bg-[var(--color-yellow-200)]", ].join(" "), + white: ["bg-withe", "text-black", "hover:bg-[var(--color-gray-100)]"], }, }, defaultVariants: { diff --git a/src/types/button.ts b/src/types/button.ts index 28d7a9c..0e9af10 100644 --- a/src/types/button.ts +++ b/src/types/button.ts @@ -6,7 +6,7 @@ export type ButtonPreset = "hero" | "feature" | "auth" | "signup" | "cta" | "bac export type Size = "sm" | "md"; export type Radius = "sm" | "md" | "lg" | "xl" | "2xl"; export type AuthColor = "black" | "white"; -export type SignupBg = "basic" | "google" | "kakao"; +export type SignupBg = "basic" | "google" | "kakao" | "white"; /** 공통 기본 타입 */ export interface BaseButtonProps extends ButtonHTMLAttributes { From 783715adeef9c167c686322821d43e56bf84b6f1 Mon Sep 17 00:00:00 2001 From: HyunseokLEE Date: Sun, 16 Nov 2025 01:12:08 +0900 Subject: [PATCH 05/12] =?UTF-8?q?CDP-206=20refactor=F0=9F=94=A8=20(link):?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99=EA=B2=BD=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/signup/SignupGroupButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/auth/signup/SignupGroupButton.tsx b/src/components/auth/signup/SignupGroupButton.tsx index c372d59..02fffd5 100644 --- a/src/components/auth/signup/SignupGroupButton.tsx +++ b/src/components/auth/signup/SignupGroupButton.tsx @@ -22,7 +22,7 @@ export const SignupGroupButton = React.forwardRef {/* 1) 일반 회원가입 → 이메일 회원가입 폼 페이지로 이동 */} - + + + + {prevHref && ( + + + + )} + + + {/* 하단 로그인 링크 */} +

+ 이미 회원이신가요?{" "} + + 로그인하기 + +

+ + ); +} diff --git a/src/types/auth.ts b/src/types/auth.ts index 0a28cdc..4d561c2 100644 --- a/src/types/auth.ts +++ b/src/types/auth.ts @@ -35,12 +35,18 @@ export interface SignupFormProps { placeholder?: string; /** autoComplete 힌트 */ autoComplete?: string; - /** 다음 버튼 라벨 (기본: "다음") */ - nextLabel?: string; - /** 이전 버튼 표시 여부 */ - showPrev?: boolean; - /** 다음 클릭(폼 submit) 콜백 */ - onNext: () => void; - /** 이전 클릭 콜백 (showPrev=true일 때만 사용) */ - onPrev?: () => void; + + /** 임시: 다음 스텝으로 이동할 링크 */ + nextHref: string; + + /** 임시: 이전 스텝으로 이동할 링크 (있을 때만 버튼 노출) */ + prevHref?: string; +} + +export interface SignupStepIndicatorProps { + /** 1부터 시작하는 현재 스텝 번호 */ + currentStep: number; + /** 전체 스텝 수 (기본 4) */ + totalSteps?: number; + className?: string; } From 82d73aaed787d7fc63cd248aa23a9d58baeaef3f Mon Sep 17 00:00:00 2001 From: HyunseokLEE Date: Sun, 16 Nov 2025 02:51:50 +0900 Subject: [PATCH 12/12] =?UTF-8?q?CDP-215=20feat=E2=9C=A8=20(signup):=20ste?= =?UTF-8?q?p=20indicator=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/signup/SignupStepIndicator.tsx | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/components/auth/signup/SignupStepIndicator.tsx diff --git a/src/components/auth/signup/SignupStepIndicator.tsx b/src/components/auth/signup/SignupStepIndicator.tsx new file mode 100644 index 0000000..b232a11 --- /dev/null +++ b/src/components/auth/signup/SignupStepIndicator.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import type { SignupStepIndicatorProps } from "@/types/auth"; + +export function SignupStepIndicator({ + currentStep, + totalSteps = 4, + className, +}: SignupStepIndicatorProps) { + const steps = Array.from({ length: totalSteps }, (_, index) => index + 1); + + return ( +
+ {steps.map((step, index) => { + const isActive = step <= currentStep; + const isLast = index === steps.length - 1; + const isCompletedConnector = step < currentStep; + + return ( +
+ {/* ● 동그라미 */} +
+ {step} +
+ + {/* ― 선 (마지막 스텝 뒤에는 없음) */} + {!isLast && ( +
+ )} +
+ ); + })} +
+ ); +}