diff --git a/package.json b/package.json
index 758c217..c770b90 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "@hookform/resolvers": "^3.9.1",
"@tanstack/react-query": "4",
"axios": "^1.7.9",
"react": "^18.3.1",
@@ -17,6 +18,7 @@
"react-hook-form": "^7.54.2",
"react-router-dom": "^7.0.2",
"styled-components": "^6.1.13",
+ "zod": "^3.24.1",
"zustand": "^5.0.2"
},
"devDependencies": {
diff --git a/src/App.tsx b/src/App.tsx
index b580cd3..f520216 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -3,16 +3,21 @@ import Header from "@components/layout/header/Header";
import Footer from "@components/layout/footer/Footer";
import GlobalStyles from "./styles/GlobalStyle";
import "@styles/font.css";
+import styled from "styled-components";
function App() {
return (
<>
-
+
>
);
}
export default App;
+
+const OuterStyle = styled(Outlet)`
+ padding: 200px 0 100px 0;
+`;
diff --git a/src/components/layout/header/HeaderStyle.ts b/src/components/layout/header/HeaderStyle.ts
index bb59e27..8498406 100644
--- a/src/components/layout/header/HeaderStyle.ts
+++ b/src/components/layout/header/HeaderStyle.ts
@@ -10,6 +10,8 @@ export const StyledHeader = styled.header`
display: flex;
justify-content: space-between;
padding: 55px 30px 0;
+ position: fixed;
+ width: 100vw;
`;
export const Logo = styled.h1`
diff --git a/src/components/ui/button/Button.tsx b/src/components/ui/button/Button.tsx
index ae24887..af78d2b 100644
--- a/src/components/ui/button/Button.tsx
+++ b/src/components/ui/button/Button.tsx
@@ -6,7 +6,7 @@ export default function Button({
onClickFnc,
type = "button",
disabled = false,
- style,
+ size,
bgColor,
textColor,
}: IButtonProps) {
@@ -15,7 +15,7 @@ export default function Button({
type={type}
onClick={onClickFnc}
disabled={disabled}
- style={style}
+ size={size}
bgColor={bgColor}
textColor={textColor}
>
diff --git a/src/components/ui/button/buttonStyle.ts b/src/components/ui/button/buttonStyle.ts
index c190717..41f70fc 100644
--- a/src/components/ui/button/buttonStyle.ts
+++ b/src/components/ui/button/buttonStyle.ts
@@ -5,9 +5,10 @@ export const Button = styled.button`
width: 100%;
border-radius: 50px;
border: 1px solid #000000;
+ text-align: center;
- ${({ style }) => {
- switch (style) {
+ ${({ size }) => {
+ switch (size) {
case "xl":
return `
height: 80px;
diff --git a/src/components/ui/button/button_props.d.ts b/src/components/ui/button/button_props.d.ts
index 082ab2e..badd89e 100644
--- a/src/components/ui/button/button_props.d.ts
+++ b/src/components/ui/button/button_props.d.ts
@@ -5,7 +5,7 @@ interface IButtonProps {
onClickFnc?: () => void;
type: "button" | "submit" | "reset";
disabled?: boolean;
- style: "xl" | "l" | "md" | "sm" | "xs";
+ size: "xl" | "l" | "md" | "sm" | "xs";
bgColor: "black" | "green" | "red" | "white" | "blue";
textColor: "black" | "gray" | "white";
}
diff --git a/src/components/ui/input/Input.tsx b/src/components/ui/input/Input.tsx
index ad8a472..32621ed 100644
--- a/src/components/ui/input/Input.tsx
+++ b/src/components/ui/input/Input.tsx
@@ -1,5 +1,7 @@
+import { useFormContext } from "react-hook-form";
import * as S from "./inputStyle";
-export default function Input({ type }: IInputProps) {
- return ;
+export default function Input({ type, keyname }: IInputProps) {
+ const { register } = useFormContext();
+ return ;
}
diff --git a/src/components/ui/input/input_props.d.ts b/src/components/ui/input/input_props.d.ts
index 717dfb0..478a3ac 100644
--- a/src/components/ui/input/input_props.d.ts
+++ b/src/components/ui/input/input_props.d.ts
@@ -1,3 +1,4 @@
interface IInputProps {
type: "text";
+ keyname: string;
}
diff --git a/src/pages/user/login/Login.tsx b/src/pages/user/login/Login.tsx
index ba5b453..a1e88dd 100644
--- a/src/pages/user/login/Login.tsx
+++ b/src/pages/user/login/Login.tsx
@@ -1,3 +1,41 @@
+import { FormProvider, useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+import Button from "../../../components/ui/button/Button";
+import * as S from "./LoginStyle";
+import { loginSchema, schema } from "./schema";
+import Input from "../../../components/ui/input/Input";
+
export default function LoginPage() {
- return Login
;
+ const methods = useForm({
+ resolver: zodResolver(schema),
+ mode: "onChange",
+ });
+ return (
+
+
+ 로그인
+
+
+
+ 이메일
+
+
+ {methods.formState.errors.email?.message}
+
+
+
+ 비밀번호
+
+
+ {methods.formState.errors.password?.message}
+
+
+
+
+
+
+
+ );
}
diff --git a/src/pages/user/login/LoginStyle.ts b/src/pages/user/login/LoginStyle.ts
new file mode 100644
index 0000000..4134641
--- /dev/null
+++ b/src/pages/user/login/LoginStyle.ts
@@ -0,0 +1,51 @@
+import styled from "styled-components";
+
+export const container = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ width: 100%;
+ gap: 50px;
+`;
+
+export const loginBox = styled.div`
+ width: 400px;
+`;
+export const label = styled.label`
+ font-weight: 500;
+ font-size: 18px;
+ color: #000000;
+`;
+
+export const title = styled.div`
+ font-weight: 700;
+ font-size: 32px;
+ color: #000000;
+`;
+
+export const inputBox = styled.div`
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ width: 100%;
+`;
+
+export const input = styled.input`
+ width: 100%;
+ height: 40px;
+ border-radius: 14px;
+ background-color: #f8f8f8;
+`;
+
+export const form = styled.form`
+ display: flex;
+ width: 100%;
+ flex-direction: column;
+ gap: 50px;
+`;
+
+export const errorMessage = styled.div`
+ color: red;
+`;
diff --git a/src/pages/user/login/schema.ts b/src/pages/user/login/schema.ts
new file mode 100644
index 0000000..3330f80
--- /dev/null
+++ b/src/pages/user/login/schema.ts
@@ -0,0 +1,13 @@
+import { z } from "zod";
+
+export const schema: z.ZodType = z.object({
+ email: z.string().email("이메일 형식이 아닙니다."),
+ password: z
+ .string()
+ .min(4, { message: "비밀번호는 최소 4자리 이상 입력해주세요." }),
+});
+
+export interface loginSchema {
+ email: string;
+ password: string;
+}
diff --git a/yarn.lock b/yarn.lock
index 7f7f071..3f21ab5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -360,6 +360,11 @@
dependencies:
levn "^0.4.1"
+"@hookform/resolvers@^3.9.1":
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-3.9.1.tgz#a23883c40bfd449cb6c6ab5a0fa0729184c950ff"
+ integrity sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==
+
"@humanfs/core@^0.19.1":
version "0.19.1"
resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz"
@@ -1714,6 +1719,11 @@ yocto-queue@^0.1.0:
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+zod@^3.24.1:
+ version "3.24.1"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.1.tgz#27445c912738c8ad1e9de1bea0359fa44d9d35ee"
+ integrity sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==
+
zustand@^5.0.2:
version "5.0.2"
resolved "https://registry.npmjs.org/zustand/-/zustand-5.0.2.tgz"