diff --git a/package.json b/package.json
index e83a19b..e4b2dd9 100644
--- a/package.json
+++ b/package.json
@@ -12,8 +12,10 @@
"dependencies": {
"axios": "^1.7.7",
"react": "^18.3.1",
+ "react-datepicker": "^7.5.0",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.2",
+ "react-toastify": "^10.0.6",
"styled-components": "^6.1.13"
},
"devDependencies": {
diff --git a/public/fonts/GowunDodum.ttf b/public/fonts/GowunDodum.ttf
new file mode 100644
index 0000000..2d87cc8
Binary files /dev/null and b/public/fonts/GowunDodum.ttf differ
diff --git a/public/images/BackgroundImage.svg b/public/images/BackgroundImage.svg
new file mode 100644
index 0000000..8dbab4e
--- /dev/null
+++ b/public/images/BackgroundImage.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/components/Letters/LetterOne.jsx b/src/components/Letters/LetterOne.jsx
new file mode 100644
index 0000000..8ebabc7
--- /dev/null
+++ b/src/components/Letters/LetterOne.jsx
@@ -0,0 +1,20 @@
+import React from "react";
+import * as S from "./styled";
+
+export const LetterOne = ({ onNext, letterContent, setLetterContent }) => {
+ const handleChange = (e) => setLetterContent(e.target.value);
+
+ return (
+
+
+
+
+ 다음
+
+
+ );
+};
diff --git a/src/components/Letters/LetterTwo.jsx b/src/components/Letters/LetterTwo.jsx
new file mode 100644
index 0000000..d54eaab
--- /dev/null
+++ b/src/components/Letters/LetterTwo.jsx
@@ -0,0 +1,116 @@
+import React, { useState } from "react";
+import * as S from "./styled";
+
+export const LetterTwo = ({
+ onPrev,
+ onSubmit,
+ receiverInfo,
+ setReceiverInfo,
+ selectedYear,
+ setSelectedYear,
+ selectedDate,
+ setSelectedDate,
+ selectedTime,
+ setSelectedTime
+}) => {
+ const handleYearChange = (date) => {
+ setSelectedYear(date);
+ setReceiverInfo((prevInfo) => ({
+ ...prevInfo,
+ year: date.getFullYear(),
+ }));
+ };
+
+ const handleDateChange = (date) => {
+ setSelectedDate(date);
+ setReceiverInfo((prevInfo) => ({
+ ...prevInfo,
+ monthDay: `${date.getMonth() + 1}-${date.getDate()}`,
+ }));
+ };
+
+ const handleTimeChange = (date) => {
+ setSelectedTime(date);
+ setReceiverInfo((prevInfo) => ({
+ ...prevInfo,
+ time: `${date.getHours()}:${date.getMinutes().toString().padStart(2, "0")}`,
+ }));
+ };
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+ setReceiverInfo((prevInfo) => ({
+ ...prevInfo,
+ [name]: value,
+ }));
+ };
+
+ return (
+
+
+ 수신인 전화번호를 입력해 주세요.
+
+ :
+
+
+
+
+
+ 몇 년도에 보낼까요?
+
+ :
+
+ 년도
+
+
+
+ 몇 월 며칠에 보낼까요?
+
+ :
+
+
+
+
+
+ 몇 시 몇 분에 보낼까요?
+
+ :
+
+
+
+
+
+
+ 이전
+ 완료
+
+
+ );
+};
diff --git a/src/components/Letters/styled.js b/src/components/Letters/styled.js
new file mode 100644
index 0000000..f84947a
--- /dev/null
+++ b/src/components/Letters/styled.js
@@ -0,0 +1,109 @@
+import styled from "styled-components";
+import backgroundImage from "/images/BackgroundImage.svg";
+import DatePicker from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
+
+
+
+export const Wrapper = styled.div`
+ position: relative;
+ width: 350px;
+ height: 540px;
+ background: url(${backgroundImage}) no-repeat center center fixed;
+ background-size: cover;
+ box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.25);
+`;
+
+export const Wrapper2 = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: space-evenly;
+ align-items: center;
+ position: relative;
+ width: 350px;
+ height: 540px;
+ background: url(${backgroundImage}) no-repeat center center fixed;
+ background-size: cover;
+ box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.25);
+`;
+
+export const Textinput = styled.textarea`
+ width: 100%;
+ height: 100%;
+ padding: 30px;
+ outline: none;
+ resize: none;
+
+ color: ${({theme}) => theme.colors.black};
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 700;
+ line-height: 1.4;
+`;
+
+export const Button = styled.button`
+ cursor: pointer;
+
+ color: ${({theme}) => theme.colors.black};
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 700;
+`;
+
+export const Section = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ justify-content: center;
+ align-items: center;
+ gap: 20px;
+`;
+
+export const MainText = styled.div`
+ color: ${({theme}) => theme.colors.black};
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ font-size: 18px;
+ font-style: normal;
+ font-weight: 300;
+ line-height: 1.4;
+`;
+
+export const Buttons = styled.div`
+ display: flex;
+ position: absolute;
+ width: 100%;
+ bottom: 0;
+ padding: 15px;
+ justify-content: space-between;
+
+ cursor: pointer;
+`;
+
+export const Rowing = styled.div`
+ display: flex;
+ flex-direction: row;
+ width: 60%;
+ gap: 4px;
+ justify-content: space-around;
+`;
+
+export const CustomDatePicker = styled(DatePicker)`
+ color: ${({theme}) => theme.colors.black};
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 700;
+
+ background: inherit;
+ outline: none;
+ display: flex;
+ width: 80px;
+
+ transform: translateY(5px);
+`;
\ No newline at end of file
diff --git a/src/components/common/Toasts/ToastOne.jsx b/src/components/common/Toasts/ToastOne.jsx
new file mode 100644
index 0000000..0588da7
--- /dev/null
+++ b/src/components/common/Toasts/ToastOne.jsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { ToastContainer } from "react-toastify";
+import "react-toastify/dist/ReactToastify.css";
+
+const ToastOne = () => {
+ return (
+
+ );
+};
+
+export default ToastOne;
diff --git a/src/components/layout/footer/Footer.jsx b/src/components/layout/footer/Footer.jsx
index 857fd3a..2ea10b4 100644
--- a/src/components/layout/footer/Footer.jsx
+++ b/src/components/layout/footer/Footer.jsx
@@ -1,9 +1,15 @@
+import React from "react";
import * as S from "./styled";
+import { useNavigate } from "react-router-dom";
export const Footer = () => {
+ const navigation = useNavigate();
+
return (
- <>
-
- >
- )
-}
\ No newline at end of file
+
+ navigation("/homepage")}>홈
+ navigation("/letter")}>편지 작성하기
+ navigation("/inventory")}>편지 보관함
+
+ );
+};
\ No newline at end of file
diff --git a/src/components/layout/footer/styled.js b/src/components/layout/footer/styled.js
index 38f3eeb..e264fb3 100644
--- a/src/components/layout/footer/styled.js
+++ b/src/components/layout/footer/styled.js
@@ -1 +1,21 @@
-import styled from "styled-components";
\ No newline at end of file
+import styled from "styled-components";
+
+export const Wrapper = styled.div`
+ display: flex;
+ width: 100%;
+ justify-content: space-evenly;
+ position: absolute;
+ bottom: 50px;
+`;
+
+export const Text = styled.div`
+ display: flex;
+
+ cursor: pointer;
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ color: ${({theme}) => theme.colors.black};
+ font-size: 20px;
+ font-weight: 400;
+ font-style: normal;
+`;
\ No newline at end of file
diff --git a/src/constant/routeConstants.js b/src/constant/routeConstants.js
index f419d03..23f1cdc 100644
--- a/src/constant/routeConstants.js
+++ b/src/constant/routeConstants.js
@@ -1,7 +1,10 @@
// src/constants/routeConstants.js
export const ROUTE_PATHS = {
- HOME: "/",
+ LOGIN: "/",
+ HOME: "/homepage",
ABOUT: "/about",
+ LETTER: "/letter",
+ INVENTORY: "/inventory",
CONTACT: "/contact",
NOT_FOUND: "*",
};
diff --git a/src/layouts/DefaultLayout.jsx b/src/layouts/DefaultLayout.jsx
index 2bf9b19..a134798 100644
--- a/src/layouts/DefaultLayout.jsx
+++ b/src/layouts/DefaultLayout.jsx
@@ -1,11 +1,17 @@
-import { Outlet } from "react-router-dom";
+import { Outlet, useLocation } from "react-router-dom";
import styled from "styled-components";
+import { Footer } from "@components/layout/footer/Footer";
const DefaultLayout = () => {
+ const location = useLocation();
+
+ const isRoot = location.pathname === "/";
+
return (
<>
+ {!isRoot && }
>
);
@@ -13,7 +19,6 @@ const DefaultLayout = () => {
const Wrapper = styled.section`
flex-grow: 1;
- background-color: ${({ theme }) => theme.colors.white};
min-height: 100vh;
`;
diff --git a/src/layouts/NotFoundLayout.jsx b/src/layouts/NotFoundLayout.jsx
index 8acde2d..4a2832c 100644
--- a/src/layouts/NotFoundLayout.jsx
+++ b/src/layouts/NotFoundLayout.jsx
@@ -15,7 +15,6 @@ const Wrapper = styled.section`
align-items: center;
justify-content: center;
flex-grow: 1;
- background-color: ${({ theme }) => theme.colors.white};
min-height: 100vh;
`;
diff --git a/src/pages/LetterInventoryPage/LetterInventoryPage.jsx b/src/pages/LetterInventoryPage/LetterInventoryPage.jsx
new file mode 100644
index 0000000..adc2897
--- /dev/null
+++ b/src/pages/LetterInventoryPage/LetterInventoryPage.jsx
@@ -0,0 +1,14 @@
+import * as S from "./styled";
+
+export const LetterInventoryPage = () => {
+ return (
+
+
+ 받은 편지
+ 보낸 편지
+
+
+ )
+}
+
+export default LetterInventoryPage;
\ No newline at end of file
diff --git a/src/pages/LetterInventoryPage/styled.js b/src/pages/LetterInventoryPage/styled.js
new file mode 100644
index 0000000..208c0bf
--- /dev/null
+++ b/src/pages/LetterInventoryPage/styled.js
@@ -0,0 +1,28 @@
+import styled from "styled-components";
+
+export const Wrapper = styled.div`
+ display: flex;
+ position: relative;
+ height: 100vh;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+`;
+
+export const MiniHeader = styled.div`
+ display: flex;
+ width: 100%;
+ justify-content: space-around;
+`;
+
+export const HeaderOption = styled.div`
+ display: flex;
+ cursor: pointer;
+
+ color: ${({theme}) => theme.colors.black};
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ font-size: 30px;
+ font-style: normal;
+ font-weight: 400;
+`;
\ No newline at end of file
diff --git a/src/pages/LetterMakePage/LetterMakePage.jsx b/src/pages/LetterMakePage/LetterMakePage.jsx
new file mode 100644
index 0000000..01c9e31
--- /dev/null
+++ b/src/pages/LetterMakePage/LetterMakePage.jsx
@@ -0,0 +1,74 @@
+import React, { useState } from "react";
+import * as S from "./styled";
+import { useNavigate } from "react-router-dom";
+import { LetterOne } from "@components/Letters/LetterOne";
+import { LetterTwo } from "@components/Letters/LetterTwo";
+import ToastOne from "@components/common/Toasts/ToastOne";
+import { toast } from "react-toastify";
+
+export const LetterMakePage = () => {
+ const [currentStep, setCurrentStep] = useState(0);
+ const [letterContent, setLetterContent] = useState(""); // 편지 내용 상태
+ const [receiverInfo, setReceiverInfo] = useState({
+ year: "",
+ monthDay: "",
+ time: "",
+ phoneNumber: "",
+ });
+
+ const [selectedYear, setSelectedYear] = useState(null);
+ const [selectedDate, setSelectedDate] = useState(null);
+ const [selectedTime, setSelectedTime] = useState(null);
+
+ const navigate = useNavigate();
+
+ const handleNextStep = () => setCurrentStep((prev) => prev + 1);
+ const handlePrevStep = () => setCurrentStep((prev) => prev - 1);
+
+ const handleSubmit = () => {
+ if (!letterContent || !receiverInfo.year || !receiverInfo.monthDay || !receiverInfo.time || !receiverInfo.phoneNumber) {
+ toast.error("모든 필수 정보를 입력해 주세요!"); // 토스트 알림 표시
+ return;
+ }
+
+ const combinedDateTime = `${receiverInfo.year}-${receiverInfo.monthDay}T${receiverInfo.time}`;
+ console.log("Submitting letter data:", letterContent);
+ console.log("Receiver Info:", {
+ ...receiverInfo,
+ dateTime: combinedDateTime,
+ });
+ navigate("/inventory");
+ };
+
+ return (
+
+ setCurrentStep(1)}>편지 작성하기
+
+ {currentStep === 1 && (
+
+ )}
+
+ {currentStep === 2 && (
+
+ )}
+
+
+ );
+};
+
+export default LetterMakePage;
diff --git a/src/pages/LetterMakePage/styled.js b/src/pages/LetterMakePage/styled.js
new file mode 100644
index 0000000..fdc9c55
--- /dev/null
+++ b/src/pages/LetterMakePage/styled.js
@@ -0,0 +1,25 @@
+import styled from "styled-components";
+
+export const Wrapper = styled.div`
+ display: flex;
+ position: relative;
+ height: 100vh;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 20px;
+`;
+
+export const MakeLetter = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ cursor: pointer;
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ color: ${({theme}) => theme.colors.black};
+ font-size: 30px;
+ font-weight: 400;
+ font-style: normal;
+`;
\ No newline at end of file
diff --git a/src/pages/LoginPage/LoginPage.jsx b/src/pages/LoginPage/LoginPage.jsx
new file mode 100644
index 0000000..ed8eb0c
--- /dev/null
+++ b/src/pages/LoginPage/LoginPage.jsx
@@ -0,0 +1,12 @@
+import * as S from "./styled";
+
+export const LoginPage = () => {
+ return (
+
+ 내일의 편지
+ 로그인
+
+ )
+}
+
+export default LoginPage;
\ No newline at end of file
diff --git a/src/pages/LoginPage/styled.js b/src/pages/LoginPage/styled.js
new file mode 100644
index 0000000..bf31a24
--- /dev/null
+++ b/src/pages/LoginPage/styled.js
@@ -0,0 +1,30 @@
+import styled from "styled-components";
+
+export const Wrapper = styled.div`
+ display: flex;
+ position: relative;
+ height: 100vh;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+`;
+
+export const MainText = styled.div`
+ display: flex;
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ color: ${({theme}) => theme.colors.black};
+ font-size: 40px;
+ font-weight: 400;
+ font-style: normal;
+`;
+
+export const Login = styled.div`
+ display: flex;
+
+ font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
+ color: ${({theme}) => theme.colors.black};
+ font-size: 30px;
+ font-weight: 400;
+ font-style: normal
+`;
\ No newline at end of file
diff --git a/src/pages/homepage/HomePage.jsx b/src/pages/homepage/HomePage.jsx
index c3adb19..741f5e5 100644
--- a/src/pages/homepage/HomePage.jsx
+++ b/src/pages/homepage/HomePage.jsx
@@ -2,9 +2,9 @@ import * as S from "./styled";
export const HomePage = () => {
return (
- <>
- 홈페이지지롱
- >
+
+ 타임캡슐 -- 설명하기
+
)
}
diff --git a/src/pages/homepage/styled.js b/src/pages/homepage/styled.js
index 38f3eeb..f97d356 100644
--- a/src/pages/homepage/styled.js
+++ b/src/pages/homepage/styled.js
@@ -1 +1,11 @@
-import styled from "styled-components";
\ No newline at end of file
+import styled from "styled-components";
+
+
+export const Wrapper = styled.div`
+ display: flex;
+ position: relative;
+ height: 100vh;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+`;
diff --git a/src/routes/router.jsx b/src/routes/router.jsx
index f71aae2..30edc2d 100644
--- a/src/routes/router.jsx
+++ b/src/routes/router.jsx
@@ -5,12 +5,19 @@ import DefaultLayout from "@layouts/DefaultLayout";
import { HomePage } from "@pages/homepage/HomePage";
import { AboutPage } from "@pages/aboutpage/AboutPage";
import { NotFoundLayout } from "@layouts/NotFoundLayout";
+import { LetterMakePage } from "@pages/LetterMakePage/LetterMakePage";
+import { LetterInventoryPage } from "@pages/LetterInventoryPage/LetterInventoryPage";
+import { LoginPage } from "@pages/LoginPage/LoginPage";
export const router = createBrowserRouter([
{
- path: ROUTE_PATHS.HOME,
+ path: ROUTE_PATHS.LOGIN,
element: ,
children: [
+ {
+ path: ROUTE_PATHS.LOGIN,
+ element: ,
+ },
{
path: ROUTE_PATHS.HOME,
element: ,
@@ -19,6 +26,14 @@ export const router = createBrowserRouter([
path: ROUTE_PATHS.ABOUT,
element: ,
},
+ {
+ path: ROUTE_PATHS.LETTER,
+ element: ,
+ },
+ {
+ path: ROUTE_PATHS.INVENTORY,
+ element: ,
+ },
],
errorElement: ,
},
diff --git a/src/styles/GlobalStyles.js b/src/styles/GlobalStyles.js
index 98cfca8..7637731 100644
--- a/src/styles/GlobalStyles.js
+++ b/src/styles/GlobalStyles.js
@@ -1,4 +1,5 @@
import { createGlobalStyle } from "styled-components";
+import backgroundImage from "/images/BackgroundImage.svg";
const GlobalStyle = createGlobalStyle`
*{box-sizing:border-box}
@@ -24,6 +25,12 @@ i {font-style:normal}
min-height: 100vh;
}
+@font-face {
+ font-family: "GowunDodum";
+ src: url("/fonts/GowunDodum.ttf") format("truetype");
+}
+
+
// 초기 html 설정
html {
/* background-color: ${({ theme }) => theme.colors.fall}; */
@@ -34,21 +41,18 @@ html {
-webkit-touch-callout: none;
-webkit-tap-highlight-color:rgb(0 0 0 / 0%);
scroll-behavior: smooth;
-
- @media (max-width: 360px) {
- font-size:12px;
- }
}
body {
width: 100%;
- max-width: 540px;
+ max-width: 428px;
overflow-x: hidden;
+ background: url(${backgroundImage}) no-repeat center center fixed;
+ background-size: cover;
background-color: ${({ theme }) => theme.colors.white};
color: ${({ theme }) => theme.colors.default};
font-family: "sans-serif";
}
-
`;
export default GlobalStyle;
diff --git a/src/styles/Theme.js b/src/styles/Theme.js
index f6e9039..86784db 100644
--- a/src/styles/Theme.js
+++ b/src/styles/Theme.js
@@ -15,12 +15,12 @@ export const theme = {
colors: {
default: "#000000",
white: "#FFFFFF",
+ black: "#000000",
},
fonts: {
- default: fontGenerator("Pretendard-Ragular", "1rem", "400", "1.5", "normal"),
+ default: fontGenerator("GowunDodum", "1rem", "400", "1.5", "normal"),
- // Apple SD 산돌고딕 Neo 폰트 설정
- Pretendard_Bold: fontGenerator("Pretendard-Bold"),
+ GowunDodum: fontGenerator("GowunDodum"),
},
};