diff --git a/package-lock.json b/package-lock.json
index 0c9ff49..c8cc238 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"path": "^0.12.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
+ "react-router-dom": "^6.27.0",
"styled-components": "^6.1.13",
"url": "^0.11.4"
},
@@ -19,6 +20,7 @@
"@types/node": "^22.8.4",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
+ "@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.3.3",
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
@@ -1017,6 +1019,15 @@
"node": ">= 8"
}
},
+ "node_modules/@remix-run/router": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz",
+ "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.3.tgz",
@@ -1321,6 +1332,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/history": {
+ "version": "4.7.11",
+ "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
+ "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -1366,6 +1384,29 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-router": {
+ "version": "5.1.20",
+ "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
+ "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/history": "^4.7.11",
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/react-router-dom": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
+ "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/history": "^4.7.11",
+ "@types/react": "*",
+ "@types/react-router": "*"
+ }
+ },
"node_modules/@types/stylis": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz",
@@ -3056,6 +3097,38 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz",
+ "integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@remix-run/router": "1.20.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz",
+ "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==",
+ "license": "MIT",
+ "dependencies": {
+ "@remix-run/router": "1.20.0",
+ "react-router": "6.27.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
diff --git a/package.json b/package.json
index 53d3b22..8b745e2 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"path": "^0.12.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
+ "react-router-dom": "^6.27.0",
"styled-components": "^6.1.13",
"url": "^0.11.4"
},
@@ -21,6 +22,7 @@
"@types/node": "^22.8.4",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
+ "@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.3.3",
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
diff --git a/src/App.tsx b/src/App.tsx
index 7654d85..47ea1eb 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -2,11 +2,13 @@
import { ThemeProvider } from "styled-components";
import theme from "@styles/theme";
import GlobalStyle from "@styles/global";
+import Router from "./Router";
function App() {
return (
+
);
}
diff --git a/src/Router.tsx b/src/Router.tsx
new file mode 100644
index 0000000..40e8ca2
--- /dev/null
+++ b/src/Router.tsx
@@ -0,0 +1,15 @@
+// Router.tsx
+import { BrowserRouter, Route, Routes } from "react-router-dom";
+import Login from "./pages/login/Login";
+
+const Router: React.FC = () => {
+ return (
+
+
+ } />
+
+
+ );
+};
+
+export default Router;
diff --git a/src/components/button/Button.tsx b/src/components/button/Button.tsx
new file mode 100644
index 0000000..d132612
--- /dev/null
+++ b/src/components/button/Button.tsx
@@ -0,0 +1,48 @@
+// Button.tsx
+
+import React from "react";
+import styled from "styled-components";
+
+const Btn = styled.button`
+ width: 350px;
+ height: 60px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: #343a40;
+ text-align: center;
+ font-size: 20px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 20px;
+ letter-spacing: -0.5px;
+ border-radius: 10px;
+ background: #99bc85;
+ cursor: pointer;
+ border: none;
+ margin: 10px auto;
+
+ @media (max-width: 360px) {
+ width: 280px;
+ }
+`;
+
+interface ButtonProps {
+ link: string;
+ name: string;
+ type: string;
+}
+
+const Button: React.FC = ({ link, name, type }) => {
+ const handleClick = () => {
+ window.location.href = link;
+ };
+
+ return (
+
+ {name}
+
+ );
+};
+
+export default Button;
diff --git a/src/components/input/DateInput.tsx b/src/components/input/DateInput.tsx
new file mode 100644
index 0000000..eebd0c2
--- /dev/null
+++ b/src/components/input/DateInput.tsx
@@ -0,0 +1,28 @@
+// DateInput.tsx
+import React from "react";
+import * as S from "./style";
+
+const DateInput: React.FC = () => {
+ return (
+
+
+ 생년월일
+ *
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default DateInput;
diff --git a/src/components/input/Input.tsx b/src/components/input/Input.tsx
new file mode 100644
index 0000000..076363e
--- /dev/null
+++ b/src/components/input/Input.tsx
@@ -0,0 +1,32 @@
+// Input.tsx
+import React from "react";
+import * as S from "./style";
+
+interface InputProps {
+ width?: string;
+ label: string;
+ essential: boolean;
+ hint: string;
+}
+
+const Input: React.FC = ({
+ width = "340px",
+ label,
+ essential = true,
+ hint,
+}) => {
+ return (
+
+
+ {label}
+ {essential && *}
+
+ {hint && {hint}}
+
+
+
+
+ );
+};
+
+export default Input;
diff --git a/src/components/input/style.ts b/src/components/input/style.ts
new file mode 100644
index 0000000..e7a8eda
--- /dev/null
+++ b/src/components/input/style.ts
@@ -0,0 +1,88 @@
+import styled from "styled-components";
+
+interface InputWrapProps {
+ width?: string;
+}
+
+export const InputContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+`;
+
+export const InputTitleWrapper = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 5px;
+`;
+
+export const InputTitle = styled.label`
+ color: #343a40;
+
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 22px;
+ letter-spacing: -0.1px;
+`;
+
+export const EssentialIcon = styled.span`
+ color: #f5535e;
+
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 18px;
+ letter-spacing: -0.1px;
+`;
+
+export const InputHint = styled.p`
+ color: #868e96;
+
+ font-size: 10px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 18px;
+ letter-spacing: -0.1px;
+`;
+
+export const InputWrap = styled.div`
+ width: ${({ width }) => width || "340px"};
+ height: 40px;
+ border-radius: 8px;
+ border: 1px solid #ced4da;
+ background: #fff;
+
+ @media (max-width: 360px) {
+ width: 280px;
+ }
+`;
+
+export const DateInputWrap = styled.div`
+ width: 102px;
+ height: 40px;
+ border-radius: 8px;
+ border: 1px solid #ced4da;
+ background: #fff;
+
+ @media (max-width: 360px) {
+ width: 82px;
+ }
+`;
+
+export const TextInput = styled.input`
+ width: 100%;
+ color: #495057;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 500;
+ letter-spacing: -0.1px;
+ outline: none;
+ padding: 10px 12px;
+ border-radius: 8px;
+`;
+
+// DateInput.tsx
+export const DateInputContainer = styled.div`
+ display: flex;
+ gap: 17px;
+`;
diff --git a/src/components/login/HintText.tsx b/src/components/login/HintText.tsx
new file mode 100644
index 0000000..ff73c49
--- /dev/null
+++ b/src/components/login/HintText.tsx
@@ -0,0 +1,39 @@
+import styled from "styled-components";
+
+const HintTextWrapper = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+`;
+
+const HintTextHeadline2 = styled.h2`
+ color: #343a40;
+ text-align: center;
+ font-family: Pretendard;
+ font-size: 28px;
+ font-style: normal;
+ font-weight: 600;
+ line-height: 40px;
+ letter-spacing: -0.5px;
+`;
+
+const HintTextP1 = styled.p`
+ color: #868e96;
+ text-align: center;
+ font-family: Pretendard;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 500;
+ line-height: 22px; /* 157.143% */
+ letter-spacing: -0.1px;
+`;
+
+export default function HintText() {
+ return (
+
+ 당신의 정보를 입력해주세요.
+ 팀을 참가할 때 간단한 정보를 입력받아요.
+
+ );
+}
diff --git a/src/pages/login/Login.tsx b/src/pages/login/Login.tsx
new file mode 100644
index 0000000..926e161
--- /dev/null
+++ b/src/pages/login/Login.tsx
@@ -0,0 +1,46 @@
+// Login.tsx
+import Input from "@components/input/Input";
+import DateInput from "@components/input/DateInput";
+import HintText from "@components/login/HintText";
+import React from "react";
+import styled from "styled-components";
+import Button from "@components/button/Button";
+
+const Container = styled.div`
+ height: calc(100vh - 80px);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 60px;
+`;
+
+const InputForm = styled.form`
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+`;
+
+const ButtonLayout = styled.div`
+ position: relative;
+ bottom: 10px;
+`;
+
+const Login: React.FC = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default Login;