diff --git a/src/App.tsx b/src/App.tsx
index 359b744..0e05801 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,6 +1,7 @@
import { Route, Routes } from 'react-router';
import useViewport from './hooks/useViewport';
+import Header from './layouts/Header';
import Home from './pages/Home';
import LetterBoardPage from './pages/LetterBoard';
import LetterBoardDetailPage from './pages/LetterBoardDetail';
@@ -34,7 +35,7 @@ const App = () => {
} />
} />
-
+ }>
} />
} />
diff --git a/src/assets/icons/alarm.svg b/src/assets/icons/alarm.svg
new file mode 100644
index 0000000..08ac647
--- /dev/null
+++ b/src/assets/icons/alarm.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/assets/icons/arrow-left.svg b/src/assets/icons/arrow-left.svg
new file mode 100644
index 0000000..e07f071
--- /dev/null
+++ b/src/assets/icons/arrow-left.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/assets/icons/index.ts b/src/assets/icons/index.ts
new file mode 100644
index 0000000..4016f3f
--- /dev/null
+++ b/src/assets/icons/index.ts
@@ -0,0 +1,5 @@
+import AlarmIcon from './alarm.svg?react';
+import ArrowLeftIcon from './arrow-left.svg?react';
+import PersonIcon from './person.svg?react';
+
+export { AlarmIcon, PersonIcon, ArrowLeftIcon };
diff --git a/src/assets/icons/person.svg b/src/assets/icons/person.svg
new file mode 100644
index 0000000..aca27fb
--- /dev/null
+++ b/src/assets/icons/person.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/src/assets/images/background-overlay.png b/src/assets/images/background-overlay.png
new file mode 100644
index 0000000..e492dbe
Binary files /dev/null and b/src/assets/images/background-overlay.png differ
diff --git a/src/assets/images/yellow-modal.png b/src/assets/images/yellow-modal.png
new file mode 100644
index 0000000..1c78c32
Binary files /dev/null and b/src/assets/images/yellow-modal.png differ
diff --git a/src/components/.gitkeep b/src/components/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/components/ConfirmModal.tsx b/src/components/ConfirmModal.tsx
new file mode 100644
index 0000000..69e67b3
--- /dev/null
+++ b/src/components/ConfirmModal.tsx
@@ -0,0 +1,58 @@
+import ModalBg from '@/assets/images/yellow-modal.png';
+
+import ModalOverlay from './ModalOverlay';
+
+interface ConfirmModalProps {
+ title: string;
+ description: string;
+ cancelText: string;
+ confirmText: string;
+ children?: React.ReactNode;
+ onCancel: () => void;
+ onConfirm: () => void;
+}
+
+const ConfirmModal = ({
+ title,
+ description,
+ cancelText,
+ confirmText,
+ children,
+ onCancel,
+ onConfirm,
+}: ConfirmModalProps) => {
+ // TODO: 배경 이미지 삽입
+ // TODO: 전역 상태로 관리해야하는지 고민
+ return (
+
+
+
+
+
+
{title}
+
{description}
+
+ {children}
+
+
+
+
+
+
+
+ );
+};
+
+export default ConfirmModal;
diff --git a/src/components/ModalOverlay.tsx b/src/components/ModalOverlay.tsx
new file mode 100644
index 0000000..2c637ab
--- /dev/null
+++ b/src/components/ModalOverlay.tsx
@@ -0,0 +1,13 @@
+interface ModalOverlayProps {
+ children: React.ReactElement;
+}
+
+const ModalOverlay = ({ children }: ModalOverlayProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default ModalOverlay;
diff --git a/src/hooks/useViewport.ts b/src/hooks/useViewport.ts
index 971b0e2..feb0447 100644
--- a/src/hooks/useViewport.ts
+++ b/src/hooks/useViewport.ts
@@ -3,8 +3,8 @@ import { useEffect } from 'react';
function useViewport() {
useEffect(() => {
const setViewport = () => {
- const vh = window.innerHeight * 0.00999;
- const vw = document.documentElement.clientWidth * 0.00999;
+ const vh = window.innerHeight * 0.01;
+ const vw = document.documentElement.clientWidth * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
document.documentElement.style.setProperty('--vw', `${vw}px`);
};
diff --git a/src/layouts/Header.tsx b/src/layouts/Header.tsx
new file mode 100644
index 0000000..2b7ebd7
--- /dev/null
+++ b/src/layouts/Header.tsx
@@ -0,0 +1,22 @@
+import { Outlet } from 'react-router';
+
+import { AlarmIcon, ArrowLeftIcon, PersonIcon } from '@/assets/icons';
+
+const Header = () => {
+ // TODO: 뒤로 가기 버튼이 보이는 조건 추가
+ // TODO: 스크롤 발생 시, 어떻게 보여져야 하는지
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default Header;
diff --git a/src/pages/MyPage/constants/index.ts b/src/pages/MyPage/constants/index.ts
new file mode 100644
index 0000000..b605b37
--- /dev/null
+++ b/src/pages/MyPage/constants/index.ts
@@ -0,0 +1,9 @@
+export const TEMPERATURE_RANGE = [
+ { min: 0, max: 10, description: '따뜻함이 필요한 따숨님' },
+ { min: 10, max: 25, description: '살짝 포근한 따숨님' },
+ { min: 25, max: 40, description: '따스한 온기를 가진 따숨님' },
+ { min: 40, max: 55, description: '마음이 따뜻한 따숨님' },
+ { min: 55, max: 70, description: '훈훈한 따숨님' },
+ { min: 70, max: 80, description: '정말 따뜻한 따숨님' },
+ { min: 85, max: 100, description: '사랑이 넘치는 따숨님' },
+];
diff --git a/src/pages/MyPage/index.tsx b/src/pages/MyPage/index.tsx
index 706b622..9554805 100644
--- a/src/pages/MyPage/index.tsx
+++ b/src/pages/MyPage/index.tsx
@@ -1,5 +1,88 @@
+import { useState } from 'react';
+
+import ConfirmModal from '@/components/ConfirmModal';
+
+import { TEMPERATURE_RANGE } from './constants';
+
+const DUMMY_TEMP = 48.5;
+const DUMMY_ZIP_CODE = '235EA';
+
const MyPage = () => {
- return MyPage
;
+ const [isOpenModal, setIsOpenModal] = useState(false);
+
+ const getDescriptionByTemperature = (temp: number) => {
+ const range = TEMPERATURE_RANGE.find((range) => temp >= range.min && temp < range.max);
+ return range?.description;
+ };
+
+ const description = getDescriptionByTemperature(DUMMY_TEMP);
+
+ return (
+ <>
+ {isOpenModal && (
+ setIsOpenModal(false)}
+ onConfirm={() => setIsOpenModal(false)}
+ />
+ )}
+
+
+ {DUMMY_ZIP_CODE.split('').map((code, index) => (
+
+ {code}
+
+ ))}
+
+
+
+
{description}
+ {DUMMY_TEMP}도
+
+
+
+
+
+
+
+
계정
+
+
로그인 정보
+
+ 카카오
+ kakaoAccount@kakao.com
+
+
+
로그아웃
+
+
+
+
+ >
+ );
};
export default MyPage;
diff --git a/src/styles/components.css b/src/styles/components.css
index d608fb9..e45dfa1 100644
--- a/src/styles/components.css
+++ b/src/styles/components.css
@@ -1,4 +1,11 @@
/* 재사용 가능한 UI 컴포넌트의 스타일 정의 */
@layer components {
+ .primary-btn {
+ @apply bg-primary-3 rounded-lg text-black;
+ }
+
+ .secondary-btn {
+ @apply bg-primary-4 rounded-lg text-gray-50;
+ }
}
diff --git a/src/styles/preflight.css b/src/styles/preflight.css
index 5e69cdd..3d0b045 100644
--- a/src/styles/preflight.css
+++ b/src/styles/preflight.css
@@ -7,11 +7,26 @@
--vw: 1vw;
}
+ * {
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+
body {
font-family: 'Pretendard Variable', Pretendard, sans-serif;
overflow-y: scroll;
overflow-x: hidden;
/* 그라데이션 배경 들어가는 곳 */
+ background:
+ url('/src/assets/images/background-overlay.png') repeat,
+ linear-gradient(
+ 180deg,
+ rgba(234, 191, 23, 0.5) 2.83%,
+ rgba(255, 245, 221, 0.5) 35.47%,
+ rgba(255, 251, 248, 0.5) 55.48%
+ ),
+ #f2f2f2;
+ background-blend-mode: overlay, normal, normal;
}
#root {
@@ -23,4 +38,8 @@
margin: 0 auto;
position: relative;
}
+
+ button {
+ cursor: pointer;
+ }
}
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
index 11f02fe..b1f45c7 100644
--- a/src/vite-env.d.ts
+++ b/src/vite-env.d.ts
@@ -1 +1,2 @@
///
+///