diff --git a/public/icon/apple_icon.svg b/public/icon/apple_icon.svg
new file mode 100644
index 0000000..8e71303
--- /dev/null
+++ b/public/icon/apple_icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/icon/apple_icon_selected.svg b/public/icon/apple_icon_selected.svg
new file mode 100644
index 0000000..a319498
--- /dev/null
+++ b/public/icon/apple_icon_selected.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/icon/close_icon.svg b/public/icon/close_icon.svg
new file mode 100644
index 0000000..76871e6
--- /dev/null
+++ b/public/icon/close_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/icon/leftarrow_icon.svg b/public/icon/leftarrow_icon.svg
new file mode 100644
index 0000000..a6e2d1f
--- /dev/null
+++ b/public/icon/leftarrow_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/icon/pen_icon.svg b/public/icon/pen_icon.svg
new file mode 100644
index 0000000..3dbe3a8
--- /dev/null
+++ b/public/icon/pen_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/icon/pen_icon_selected.svg b/public/icon/pen_icon_selected.svg
new file mode 100644
index 0000000..ce6c1a2
--- /dev/null
+++ b/public/icon/pen_icon_selected.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/App.tsx b/src/App.tsx
index a65b854..bdf2ea6 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -31,7 +31,7 @@ function App() {
} />
} />
} />
- } />
+ } />
} />
} />
diff --git a/src/components/common/Modal/ModalBackdrop.tsx b/src/components/common/Modal/ModalBackdrop.tsx
index 06e1c85..756ec8c 100644
--- a/src/components/common/Modal/ModalBackdrop.tsx
+++ b/src/components/common/Modal/ModalBackdrop.tsx
@@ -7,4 +7,5 @@ export const ModalBackdrop = styled.div`
right: 0;
top: 0;
bottom: 0;
+ z-index: 1000;
`;
diff --git a/src/components/home/PlanBox.tsx b/src/components/home/PlanBox.tsx
index db75b6b..83a3c6a 100644
--- a/src/components/home/PlanBox.tsx
+++ b/src/components/home/PlanBox.tsx
@@ -1,7 +1,9 @@
import styled, { css } from 'styled-components';
import { ProgressCircle } from './ProgressCircle';
+import { useNavigate } from 'react-router-dom';
interface PlanBoxProps {
+ planId: number;
mainplan: string;
subplans: string[];
startdate: string;
@@ -14,10 +16,22 @@ export const PlanBox = ({ ...props }: PlanBoxProps) => {
const mainColors = ['#9D9BFF', '#FFC066', '#FF7EBC', '#4ED99C'];
const darkColors = ['#6D6AFF', '#FF9600', '#FF3898', '#00AD7C'];
+ const navigate = useNavigate();
+
+ const handleClickMainText = (planId: number) => {
+ navigate(`/plan/${planId}`);
+ };
+
return (
- {props.mainplan}
+ {
+ handleClickMainText(props.planId);
+ }}
+ >
+ {props.mainplan}
+
{props.startdate}~
diff --git a/src/components/plan/BackBtn.tsx b/src/components/plan/BackBtn.tsx
new file mode 100644
index 0000000..82924de
--- /dev/null
+++ b/src/components/plan/BackBtn.tsx
@@ -0,0 +1,41 @@
+import styled from 'styled-components';
+import { useNavigate } from 'react-router-dom';
+
+export const BackBtn = () => {
+ const navigate = useNavigate();
+
+ const handleClickBtn = () => {
+ navigate('/home');
+ };
+
+ return (
+
+
+
+ );
+};
+
+const BackButton = styled.button`
+ position: absolute;
+ top: 30px;
+ left: 30px;
+ width: 28px;
+ height: 28px;
+
+ border-radius: 50%;
+ border: none;
+ background-color: ${({ theme }) => theme.colors.green};
+ z-index: 300;
+
+ img {
+ width: 22px;
+ height: 22px;
+ }
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
diff --git a/src/components/plan/PlanContent.tsx b/src/components/plan/PlanContent.tsx
index ccdbebe..de08a9f 100644
--- a/src/components/plan/PlanContent.tsx
+++ b/src/components/plan/PlanContent.tsx
@@ -16,9 +16,12 @@ export const PlanContent = () => {
const PlanContentContainer = styled.div`
position: absolute;
- top: 0;
+ top: 40px;
left: 50%;
transform: translate(-50%, 0);
`;
-const BackgroundImg = styled.img``;
+const BackgroundImg = styled.img`
+ border: none;
+ outline: none;
+`;
diff --git a/src/components/plan/PlanLayout.tsx b/src/components/plan/PlanLayout.tsx
index 237bef2..6d7d50b 100644
--- a/src/components/plan/PlanLayout.tsx
+++ b/src/components/plan/PlanLayout.tsx
@@ -2,7 +2,6 @@ import styled from 'styled-components';
import { TopImgContent } from './TopImgContent';
import { PlanContent } from './PlanContent';
-import { BottomContent } from './BottomContent';
export const PlanLayout = () => {
return (
@@ -12,8 +11,6 @@ export const PlanLayout = () => {
{/*계획표 이미지, 텍스트*/}
- {/*이미지 저장 버튼*/}
-
{/*상단 이미지들*/}
@@ -21,8 +18,10 @@ export const PlanLayout = () => {
};
const LayoutContainer = styled.div`
+ padding-top: 40px;
height: 100vh;
position: relative;
+ background-color: #ccedff;
`;
const TopBackground = styled.div`
@@ -33,7 +32,7 @@ const TopBackground = styled.div`
const BottomBackground = styled.div`
width: 100%;
- height: 80px;
+ height: 100%;
//height: calc(100vh - 500px);
background-color: #8cd27b;
`;
diff --git a/src/components/plan/TopImgContent.tsx b/src/components/plan/TopImgContent.tsx
index e622e31..6b783e6 100644
--- a/src/components/plan/TopImgContent.tsx
+++ b/src/components/plan/TopImgContent.tsx
@@ -25,7 +25,7 @@ const TopImgContentContainer = styled.div`
const CloudImg = styled.img`
position: absolute;
- top: 15px;
+ top: 60px;
left: 15px;
width: 120px;
diff --git a/src/components/plan/ViewToggle.tsx b/src/components/plan/ViewToggle.tsx
new file mode 100644
index 0000000..f15da07
--- /dev/null
+++ b/src/components/plan/ViewToggle.tsx
@@ -0,0 +1,101 @@
+import styled from 'styled-components';
+
+enum PlanView {
+ Image = 'Image',
+ Graph = 'Graph',
+}
+interface ViewToggleProps {
+ view: PlanView;
+ setView: React.Dispatch>;
+}
+export const ViewToggle = ({ view, setView }: ViewToggleProps) => {
+ const handleClickToggleBtn = () => {
+ if (view === PlanView.Image) setView(PlanView.Graph);
+ else setView(PlanView.Image);
+ };
+ return (
+
+
+ {view === PlanView.Image ? (
+
+ ) : (
+
+ )}
+ 꿈틀나무
+
+
+ {view === PlanView.Graph ? (
+
+ ) : (
+
+ )}
+ 만다라트
+
+
+ );
+};
+
+const ViewToggleContainer = styled.div`
+ position: absolute;
+ top: 28px;
+ left: 50%;
+ transform: translate(-50%, 0);
+ z-index: 300;
+
+ width: 140px;
+ height: 32px;
+ padding: 4px;
+ border-radius: 8px;
+
+ background-color: ${({ theme }) => theme.colors.gray_300};
+
+ display: flex;
+ justify-content: space-between;
+`;
+
+const ToggleBtn = styled.button`
+ width: 64px;
+ height: 24px;
+ border-radius: 4px;
+ padding: 0;
+ border: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ font-family: 'PretendardMedium';
+ font-size: 12px;
+ background-color: ${({ theme }) => theme.colors.gray_300};
+ color: ${({ theme }) => theme.colors.gray_600};
+ &.selected {
+ background-color: white;
+ color: ${({ theme }) => theme.colors.green};
+ box-shadow: 1px 1px 8px 0px #d9d9d9;
+ }
+
+ img {
+ width: 12px;
+ height: 12px;
+ margin-right: 2px;
+ }
+
+ transition: background-color 0.1s ease;
+`;
diff --git a/src/components/planedit/DoneModal.tsx b/src/components/planedit/DoneModal.tsx
new file mode 100644
index 0000000..7fc7174
--- /dev/null
+++ b/src/components/planedit/DoneModal.tsx
@@ -0,0 +1,102 @@
+import styled from 'styled-components';
+import { Modal } from '@components/common/Modal';
+import { ModalHeader, HeaderContent, CloseBtn } from './EditModal';
+
+interface DoneModalProps {
+ isOpenModal: boolean;
+ setIsOpenModal: React.Dispatch>;
+ plan: string;
+}
+export const DoneModal = ({
+ isOpenModal,
+ setIsOpenModal,
+ plan,
+}: DoneModalProps) => {
+ return (
+
+
+
+ 목표 완료
+ {
+ setIsOpenModal(false);
+ }}
+ >
+
+
+
+
+ "{plan}"
+ 목표를 완료하셨나요?
+
+
+ 아직이에요
+ 완료했어요
+
+
+
+ );
+};
+
+const DoneModalContainer = styled.div``;
+
+const PlanContent = styled.div`
+ width: 100%;
+ height: 100px;
+ margin: 8px 0;
+
+ display: flex;
+ flex-direction: column;
+ justify-content: space-evenly;
+`;
+
+const PlanText = styled.div`
+ width: 100%;
+ font-family: 'Pretendard';
+ color: ${({ theme }) => theme.colors.green};
+ text-align: center;
+`;
+const GuideText = styled.div`
+ width: 100%;
+ text-align: center;
+
+ font-family: 'PretendardMedium';
+ font-size: 12px;
+ color: ${({ theme }) => theme.colors.gray_900};
+`;
+
+const BottomBtnContainer = styled.div`
+ display: flex;
+ justify-content: space-between;
+`;
+
+const BottomBtn = styled.button`
+ width: 132px;
+ height: 28px;
+ border-radius: 4px;
+ border: none;
+ padding: 0;
+
+ font-family: 'Pretendard';
+ font-size: 11px;
+`;
+
+export const CancelBtn = styled(BottomBtn)`
+ background-color: white;
+ border: 1px solid ${({ theme }) => theme.colors.green};
+ color: ${({ theme }) => theme.colors.green};
+`;
+
+export const DoneBtn = styled(BottomBtn)`
+ background-color: ${({ theme }) => theme.colors.green};
+ color: white;
+`;
diff --git a/src/components/planedit/EditButtons.tsx b/src/components/planedit/EditButtons.tsx
new file mode 100644
index 0000000..00f8e50
--- /dev/null
+++ b/src/components/planedit/EditButtons.tsx
@@ -0,0 +1,59 @@
+import styled from 'styled-components';
+import { contentState } from './PlanEditContent';
+
+interface EditButtonsProps {
+ content: contentState;
+ setContent: React.Dispatch>;
+}
+export const EditButtons = ({ content, setContent }: EditButtonsProps) => {
+ return (
+
+ {
+ setContent(contentState.Edit);
+ }}
+ >
+ 목표 수정하기
+
+ {
+ setContent(contentState.Done);
+ }}
+ >
+ 목표 완료하기
+
+
+ );
+};
+
+const EditButtonsContainer = styled.div`
+ display: flex;
+ justify-content: space-around;
+
+ width: 390px;
+
+ &.hide {
+ display: none;
+ }
+`;
+
+const Button = styled.button`
+ width: 180px;
+ height: 32px;
+ border-radius: 8px;
+
+ border: none;
+ color: white;
+ font-family: 'PretendardMedium';
+ font-size: 12px;
+`;
+
+const EditBtn = styled(Button)`
+ background-color: #9d9bff;
+`;
+
+const DoneBtn = styled(Button)`
+ background-color: #ff7ebc;
+`;
diff --git a/src/components/planedit/EditModal.tsx b/src/components/planedit/EditModal.tsx
new file mode 100644
index 0000000..f458492
--- /dev/null
+++ b/src/components/planedit/EditModal.tsx
@@ -0,0 +1,109 @@
+import styled from 'styled-components';
+import { Modal } from '@components/common/Modal';
+
+interface EditModalProps {
+ isOpenModal: boolean;
+ setIsOpenModal: React.Dispatch>;
+}
+export const EditModal = ({ isOpenModal, setIsOpenModal }: EditModalProps) => {
+ return (
+
+
+
+ 목표 수정
+ {
+ setIsOpenModal(false);
+ }}
+ >
+
+
+
+
+
+ 취소
+ 편집 완료
+
+
+
+ );
+};
+
+const EditModalContainer = styled.div`
+ border-radius: 4px;
+ background-color: white;
+`;
+
+export const ModalHeader = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+`;
+
+export const HeaderContent = styled.div`
+ font-family: 'PretendardMedium';
+ font-size: 13px;
+ color: ${({ theme }) => theme.colors.gray_900};
+`;
+
+export const CloseBtn = styled.button`
+ background-color: transparent;
+ border: none;
+ padding: 0;
+
+ img {
+ width: 16px;
+ height: 16px;
+ }
+`;
+
+const EditTextArea = styled.textarea`
+ width: 230px;
+ height: 100px;
+ padding: 12px;
+ margin-top: 6px;
+
+ border: none;
+ background-color: ${({ theme }) => theme.colors.gray_200};
+ border-radius: 2px;
+ outline: none;
+
+ font-family: 'Pretendard';
+`;
+
+const BottomBtnContainer = styled.div`
+ display: flex;
+ justify-content: space-between;
+ margin-top: 6px;
+`;
+
+const BottomBtn = styled.button`
+ width: 112px;
+ height: 24px;
+ border-radius: 4px;
+ border: none;
+ padding: 0;
+
+ font-family: 'Pretendard';
+ font-size: 11px;
+`;
+
+export const CancelBtn = styled(BottomBtn)`
+ background-color: white;
+ border: 1px solid ${({ theme }) => theme.colors.green};
+ color: ${({ theme }) => theme.colors.green};
+`;
+
+export const DoneBtn = styled(BottomBtn)`
+ background-color: ${({ theme }) => theme.colors.green};
+ color: white;
+`;
diff --git a/src/components/planedit/PlanEditContent.tsx b/src/components/planedit/PlanEditContent.tsx
new file mode 100644
index 0000000..3e1c08e
--- /dev/null
+++ b/src/components/planedit/PlanEditContent.tsx
@@ -0,0 +1,34 @@
+import styled from 'styled-components';
+import { useState } from 'react';
+
+import { EditButtons } from './EditButtons';
+import { EditModal } from './EditModal';
+import { DoneModal } from './DoneModal';
+
+export enum contentState {
+ Default = 'Default',
+ Edit = 'Edit',
+ Done = 'Done',
+}
+export const PlanEditContent = () => {
+ const [content, setContent] = useState(contentState.Default);
+ const [isOpenEditModal, setIsOpenEditModal] = useState(false);
+ const [isOpenDoneModal, setIsOpenDoneModal] = useState(true);
+
+ return (
+
+
+
+
+
+ );
+};
+
+const PlanEditContentContainer = styled.div``;
diff --git a/src/components/planimg/index.tsx b/src/components/planimg/index.tsx
index 7c932c2..dad24a7 100644
--- a/src/components/planimg/index.tsx
+++ b/src/components/planimg/index.tsx
@@ -99,7 +99,7 @@ const StyledMiddleTableCell = styled.div<{ order?: string }>`
`;
interface PropsType {
- refLink: React.RefObject;
+ refLink?: React.RefObject;
}
export const PlanImg = ({ refLink }: PropsType) => {
@@ -150,7 +150,7 @@ export const PlanImg = ({ refLink }: PropsType) => {
const Container = styled.div`
width: 390px;
height: 390px;
- margin-bottom: 50px;
+ margin-bottom: 30px;
`;
export const StyledBigTable = styled.div`
diff --git a/src/pages/Home/index.tsx b/src/pages/Home/index.tsx
index 81172d0..04e3dd2 100644
--- a/src/pages/Home/index.tsx
+++ b/src/pages/Home/index.tsx
@@ -6,28 +6,28 @@ import { AddPlanBtn } from '@components/home/AddPlanBtn';
const data = [
{
- mainplan: '개발자로 취업하기',
+ mainplan: '1년 안에 백엔드 개발자로 취업하기',
subplans: ['자기계발', '네트워킹', '프로젝트', '학습'],
startdate: '2023.05.12',
- percent: 50,
+ percent: 64,
},
{
- mainplan: '개발자로 취업하기',
- subplans: ['자기계발', '네트워킹', '프로젝트', '학습'],
- startdate: '2023.05.12',
- percent: 50,
+ mainplan: '20년 안에 내집 마련하기',
+ subplans: ['부동산 투자', '주택청약', '재테크', '경제 공부'],
+ startdate: '2023.01.01',
+ percent: 10,
},
{
- mainplan: '개발자로 취업하기',
- subplans: ['자기계발', '네트워킹', '프로젝트', '학습'],
- startdate: '2023.05.12',
- percent: 50,
+ mainplan: '하프 마라톤 완주하기',
+ subplans: ['기록관리', '러닝크루', '근력운동', '체중관리'],
+ startdate: '2023.08.30',
+ percent: 36,
},
{
- mainplan: '개발자로 취업하기',
- subplans: ['자기계발', '네트워킹', '프로젝트', '학습'],
+ mainplan: '대학교 졸업',
+ subplans: ['학점 관리', '졸업 프로젝트', '졸업 논문', '졸업 시험'],
startdate: '2023.05.12',
- percent: 50,
+ percent: 82,
},
];
@@ -39,6 +39,7 @@ export const HomePage = () => {
return (
{
+ return (
+
+
+
+
+ );
+};
+
+const PlanEditLayoutContainer = styled.div`
+ padding-top: 100px;
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+`;
diff --git a/src/pages/Plan/index.tsx b/src/pages/Plan/index.tsx
index 3e927f4..88c5ca7 100644
--- a/src/pages/Plan/index.tsx
+++ b/src/pages/Plan/index.tsx
@@ -1,19 +1,25 @@
-import { useRecoilValueLoadable } from 'recoil';
-import { mandalartPlan } from '@recoil/plan';
-
-import { Loading } from './Loading';
-import { Plan } from './Plan';
-import { ErrorPage } from '@pages/Error';
+import styled from 'styled-components';
+import { useState } from 'react';
+import { PlanLayout } from '@components/plan/PlanLayout';
+import { PlanEditLayout } from './PlanEditLayout';
+import { BackBtn } from '@components/plan/BackBtn';
+import { ViewToggle } from '@components/plan/ViewToggle';
+enum PlanView {
+ Image = 'Image',
+ Graph = 'Graph',
+}
export const PlanPage = () => {
- const planLodable = useRecoilValueLoadable(mandalartPlan);
-
- switch (planLodable.state) {
- case 'hasValue':
- return ;
- case 'loading':
- return ;
- case 'hasError':
- return ;
- }
+ const [view, setView] = useState(PlanView.Image);
+ return (
+
+
+
+ {view === PlanView.Image ? : }
+
+ );
};
+
+const PlanPageContainer = styled.div`
+ position: relative;
+`;
diff --git a/src/pages/Plan/index_.tsx b/src/pages/Plan/index_.tsx
new file mode 100644
index 0000000..3e927f4
--- /dev/null
+++ b/src/pages/Plan/index_.tsx
@@ -0,0 +1,19 @@
+import { useRecoilValueLoadable } from 'recoil';
+import { mandalartPlan } from '@recoil/plan';
+
+import { Loading } from './Loading';
+import { Plan } from './Plan';
+import { ErrorPage } from '@pages/Error';
+
+export const PlanPage = () => {
+ const planLodable = useRecoilValueLoadable(mandalartPlan);
+
+ switch (planLodable.state) {
+ case 'hasValue':
+ return ;
+ case 'loading':
+ return ;
+ case 'hasError':
+ return ;
+ }
+};