diff --git a/src/App.tsx b/src/App.tsx index e7907ab..8cff189 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,9 @@ import React from 'react'; import { Route, Routes } from 'react-router-dom'; import { Home, Write, InputPage, Temp, NoPage } from 'pages'; import Post from 'pages/post'; +import My from 'pages/my'; +import Edit from 'pages/my/edit'; +import Cancle from 'pages/my/cancle'; function App() { return ( @@ -12,6 +15,9 @@ function App() { } /> } /> } /> + } /> + } /> + } /> ); } diff --git a/src/components/Modal/ImageChange/index.tsx b/src/components/Modal/ImageChange/index.tsx new file mode 100644 index 0000000..05a9f01 --- /dev/null +++ b/src/components/Modal/ImageChange/index.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import * as S from './style'; +import XIcon from 'svg/XIcon'; +import ChangeIcon from 'svg/ChangeIcon'; + +interface Props { + onClose: () => void; +} + +const ImageChange = ({ onClose }: Props) => { + return ( + + + + 프로필 변경 +
+ +
+
+ + + +
+ 확인 +
+ ); +}; + +export default ImageChange; diff --git a/src/components/Modal/ImageChange/style.ts b/src/components/Modal/ImageChange/style.ts new file mode 100644 index 0000000..5e498f0 --- /dev/null +++ b/src/components/Modal/ImageChange/style.ts @@ -0,0 +1,73 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + width: 400px; + padding: 24px; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 28px; + background-color: ${({ theme }) => theme.color.white}; + border-radius: 8px; +`; + +export const Header = styled.div` + display: flex; + justify-content: space-between; + align-items: flex-start; + align-self: stretch; + background-color: ${({ theme }) => theme.color.white}; +`; + +export const CloseButton = styled.div``; + +export const Title = styled.div` + ${({ theme }) => theme.fontStyle.m1.semi}; + color: ${({ theme }) => theme.color.black}; +`; + +export const Hidden = styled.input` + display: none; +`; + +export const ChangeButton = styled.div` + position: absolute; + top: 0; + right: 0; + width: 40px; + height: 40px; + border-radius: 0px 8px; + background: ${({ theme }) => theme.color.gray[400]}; + display: flex; + justify-content: center; + align-items: center; +`; + +export const ImageBack = styled.div` + position: relative; + width: 352px; + height: 345px; + border-radius: 8px; + background: ${({ theme }) => theme.color.gray[300]}; +`; + +export const CheckButton = styled.div` + padding: 10px 16px; + display: flex; + justify-content: center; + align-items: center; + align-self: stretch; + gap: 10px; + border-radius: 8px; + background-color: ${({ theme }) => theme.color.main}; + color: ${({ theme }) => theme.color.white}; + ${({ theme }) => theme.fontStyle.m3.semi}; +`; + +export const ProfileContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; +`; diff --git a/src/components/My/CanclePage/PostHeader/index.tsx b/src/components/My/CanclePage/PostHeader/index.tsx new file mode 100644 index 0000000..f8e5444 --- /dev/null +++ b/src/components/My/CanclePage/PostHeader/index.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import * as S from './style'; +import { LeftArrow } from 'svg'; +import { useNavigate } from 'react-router-dom'; + +const PostHeader = () => { + const navigate = useNavigate(); + + return ( + + navigate(`/my`)}> + + + 글보기 + + + ); +}; + +export default PostHeader; diff --git a/src/components/My/CanclePage/PostHeader/style.ts b/src/components/My/CanclePage/PostHeader/style.ts new file mode 100644 index 0000000..8f1cf5a --- /dev/null +++ b/src/components/My/CanclePage/PostHeader/style.ts @@ -0,0 +1,24 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + max-width: 37.5rem; + width: 100%; + padding: 1rem 0.75rem; + display: flex; + justify-content: space-between; + align-items: center; +`; + +export const HomeButton = styled.div` + cursor: pointer; +`; + +export const Text = styled.p` + ${({ theme }) => theme.fontStyle.m2} + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const Empty = styled.div` + width: 24px; + height: 25px; +`; diff --git a/src/components/My/CanclePage/PostProfile/index.tsx b/src/components/My/CanclePage/PostProfile/index.tsx new file mode 100644 index 0000000..f8bb444 --- /dev/null +++ b/src/components/My/CanclePage/PostProfile/index.tsx @@ -0,0 +1,36 @@ +import React, { useState } from 'react'; +import * as S from './style'; +import KebabIcon from 'svg/KebabIcon'; + +const PostProfile = () => { + const [modal, setModal] = useState(false); + return ( + + + + + 한재형 + + 광주소프트웨어마이스터고등학교 + + 1학년 + + 여자 + + + + + setModal(!modal)}> + + + {modal && ( + + 글 삭제 + + )} + + + ); +}; + +export default PostProfile; diff --git a/src/components/My/CanclePage/PostProfile/style.ts b/src/components/My/CanclePage/PostProfile/style.ts new file mode 100644 index 0000000..98ced9e --- /dev/null +++ b/src/components/My/CanclePage/PostProfile/style.ts @@ -0,0 +1,75 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + justify-content: space-between; +`; + +export const Profile = styled.div` + display: flex; + align-items: center; + gap: 0.75rem; +`; + +export const ProfileImg = styled.img` + width: 3rem; + height: 3rem; + border-radius: 100%; +`; + +export const ProfileText = styled.div` + display: flex; + flex-direction: column; + gap: 0.125rem; +`; + +export const Name = styled.span` + ${({ theme }) => theme.fontStyle.label}; + color: ${({ theme }) => theme.color.gray[600]}; +`; + +export const Data = styled.div` + display: flex; + align-items: center; + gap: 0.25rem; +`; + +export const DataText = styled.span` + ${({ theme }) => theme.fontStyle.label}; + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const Dot = styled.div` + width: 0.25rem; + height: 0.25rem; + border-radius: 0.125rem; + background-color: #b4b5b7; +`; + +export const ModalContainer = styled.div` + position: relative; + display: flex; + justify-content: center; + align-items: center; +`; + +export const DetailButton = styled.div``; + +export const DetailModal = styled.div` + position: absolute; + left: -78px; + top: 40px; + display: inline-flex; + padding: 24px; + flex-direction: column; + align-items: flex-start; + gap: 32px; + border-radius: 8px; + background: ${({ theme }) => theme.color.white}; + box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.08); +`; + +export const WarningText = styled.div` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.system}; +`; diff --git a/src/components/My/CanclePage/index.tsx b/src/components/My/CanclePage/index.tsx new file mode 100644 index 0000000..be0ac3b --- /dev/null +++ b/src/components/My/CanclePage/index.tsx @@ -0,0 +1,55 @@ +import React, { useState } from 'react'; +import * as S from './style'; +import Profile from './PostProfile'; +import MateList from 'components/MateList'; +import { ReportIcon } from 'svg'; +import { DeclarationModal } from 'components/Modal'; +import TagList from '../PostList/PostCard/TagList'; +import PostHeader from './PostHeader'; + +const CanclePage = () => { + const [modal, setModal] = useState(false); + return ( + <> + + + + + + + 같이 산책 하실 분 구해요 + + 토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 사람 + + + + 카톡 : wjdtjffl55 + 디스코드 : hye_2417 + 인스타그램 : hye_2417 + + 마감일 : 2024년 06월 17일 + + 2자리 남음 + + + + setModal(true)}> + + + + + + + 신청 취소 + + {modal && setModal(false)} postId={1} />} + + ); +}; + +export default CanclePage; diff --git a/src/components/My/CanclePage/style.ts b/src/components/My/CanclePage/style.ts new file mode 100644 index 0000000..285833a --- /dev/null +++ b/src/components/My/CanclePage/style.ts @@ -0,0 +1,142 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + padding: 1.75rem 1.5rem; + max-width: 37.5rem; + width: 100%; + display: flex; + flex-direction: column; + gap: 2.5rem; + border: 1px solid ${({ theme }) => theme.color.gray[100]}; + border-radius: 0.5rem; +`; + +export const PostContainer = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 1.75rem; +`; + +export const ApplyContainer = styled.div` + display: flex; + flex-direction: column; + gap: 20px; +`; + +export const PostText = styled.div` + display: flex; + flex-direction: column; + gap: 8px; +`; + +export const Title = styled.div` + ${({ theme }) => theme.fontStyle.h4.semi} + color: ${({ theme }) => theme.color.black}; +`; + +export const Content = styled.div` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.black}; +`; + +export const SNSContainer = styled.div` + display: flex; + flex-direction: column; + gap: 0.25rem; +`; + +export const SNSText = styled(Content)``; + +export const Deadline = styled(Content)``; + +export const PostData = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + gap: 1rem; +`; + +export const Remain = styled.span` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const TagReportContainer = styled.div` + display: flex; + justify-content: space-between; +`; + +export const ReportButton = styled.div` + cursor: pointer; +`; + +export const CancleButton = styled.button` + ${({ theme }) => theme.fontStyle.m3.semi}; + color: ${({ theme }) => theme.color.white}; + border: none; + border-radius: 0.5rem; + background: ${({ theme }) => theme.color.system}; + display: flex; + padding: 0.75rem 1.75rem; + justify-content: center; + align-items: center; + gap: 0.625rem; + cursor: pointer; +`; + +export const Line = styled.div` + background: ${({ theme }) => theme.color.gray[200]}; +`; + +export const ApplicantList = styled.div` + display: flex; + width: 600px; + flex-direction: column; + gap: 28px; +`; + +export const ApplicantContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +`; + +export const ProfileText = styled.div` + display: flex; + gap: 8px; +`; + +export const Name = styled.span` + ${({ theme }) => theme.fontStyle.m2.semi}; + color: ${({ theme }) => theme.color.black}; +`; + +export const Data = styled.div` + display: flex; + align-items: center; + gap: 0.25rem; +`; + +export const DataText = styled.span` + ${({ theme }) => theme.fontStyle.label}; + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const Dot = styled.div` + width: 0.25rem; + height: 0.25rem; + border-radius: 0.125rem; + background-color: #b4b5b7; +`; + +export const OutButton = styled.div` + display: flex; + padding: 8px 12px; + justify-content: center; + align-items: center; + gap: 10px; + border-radius: 8px; + background: ${({ theme }) => theme.color.system}; + color: ${({ theme }) => theme.color.white}; +`; diff --git a/src/components/My/DetailPost/PostHeader/index.tsx b/src/components/My/DetailPost/PostHeader/index.tsx new file mode 100644 index 0000000..f8e5444 --- /dev/null +++ b/src/components/My/DetailPost/PostHeader/index.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import * as S from './style'; +import { LeftArrow } from 'svg'; +import { useNavigate } from 'react-router-dom'; + +const PostHeader = () => { + const navigate = useNavigate(); + + return ( + + navigate(`/my`)}> + + + 글보기 + + + ); +}; + +export default PostHeader; diff --git a/src/components/My/DetailPost/PostHeader/style.ts b/src/components/My/DetailPost/PostHeader/style.ts new file mode 100644 index 0000000..8f1cf5a --- /dev/null +++ b/src/components/My/DetailPost/PostHeader/style.ts @@ -0,0 +1,24 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + max-width: 37.5rem; + width: 100%; + padding: 1rem 0.75rem; + display: flex; + justify-content: space-between; + align-items: center; +`; + +export const HomeButton = styled.div` + cursor: pointer; +`; + +export const Text = styled.p` + ${({ theme }) => theme.fontStyle.m2} + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const Empty = styled.div` + width: 24px; + height: 25px; +`; diff --git a/src/components/My/DetailPost/PostProfile/index.tsx b/src/components/My/DetailPost/PostProfile/index.tsx new file mode 100644 index 0000000..f8bb444 --- /dev/null +++ b/src/components/My/DetailPost/PostProfile/index.tsx @@ -0,0 +1,36 @@ +import React, { useState } from 'react'; +import * as S from './style'; +import KebabIcon from 'svg/KebabIcon'; + +const PostProfile = () => { + const [modal, setModal] = useState(false); + return ( + + + + + 한재형 + + 광주소프트웨어마이스터고등학교 + + 1학년 + + 여자 + + + + + setModal(!modal)}> + + + {modal && ( + + 글 삭제 + + )} + + + ); +}; + +export default PostProfile; diff --git a/src/components/My/DetailPost/PostProfile/style.ts b/src/components/My/DetailPost/PostProfile/style.ts new file mode 100644 index 0000000..98ced9e --- /dev/null +++ b/src/components/My/DetailPost/PostProfile/style.ts @@ -0,0 +1,75 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + justify-content: space-between; +`; + +export const Profile = styled.div` + display: flex; + align-items: center; + gap: 0.75rem; +`; + +export const ProfileImg = styled.img` + width: 3rem; + height: 3rem; + border-radius: 100%; +`; + +export const ProfileText = styled.div` + display: flex; + flex-direction: column; + gap: 0.125rem; +`; + +export const Name = styled.span` + ${({ theme }) => theme.fontStyle.label}; + color: ${({ theme }) => theme.color.gray[600]}; +`; + +export const Data = styled.div` + display: flex; + align-items: center; + gap: 0.25rem; +`; + +export const DataText = styled.span` + ${({ theme }) => theme.fontStyle.label}; + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const Dot = styled.div` + width: 0.25rem; + height: 0.25rem; + border-radius: 0.125rem; + background-color: #b4b5b7; +`; + +export const ModalContainer = styled.div` + position: relative; + display: flex; + justify-content: center; + align-items: center; +`; + +export const DetailButton = styled.div``; + +export const DetailModal = styled.div` + position: absolute; + left: -78px; + top: 40px; + display: inline-flex; + padding: 24px; + flex-direction: column; + align-items: flex-start; + gap: 32px; + border-radius: 8px; + background: ${({ theme }) => theme.color.white}; + box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.08); +`; + +export const WarningText = styled.div` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.system}; +`; diff --git a/src/components/My/DetailPost/index.tsx b/src/components/My/DetailPost/index.tsx new file mode 100644 index 0000000..2eb3888 --- /dev/null +++ b/src/components/My/DetailPost/index.tsx @@ -0,0 +1,75 @@ +import React, { useState } from 'react'; +import * as S from './style'; +import Profile from './PostProfile'; +import MateList from 'components/MateList'; +import { ReportIcon } from 'svg'; +import { DeclarationModal } from 'components/Modal'; +import TagList from '../PostList/PostCard/TagList'; +import PostHeader from './PostHeader'; + +const DetailPost = () => { + const [modal, setModal] = useState(false); + return ( + <> + + + + + + + 같이 산책 하실 분 구해요 + + 토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 + 사람토요일에 호수공원 산책할 사람토요일에 호수공원 산책할 사람 + + + + 카톡 : wjdtjffl55 + 디스코드 : hye_2417 + 인스타그램 : hye_2417 + + 마감일 : 2024년 06월 17일 + + 2자리 남음 + + + + setModal(true)}> + + + + + + + 글 수정 + { + + + {[...Array(3)].map((_, idx) => ( + + + 한재형 + + 광주소프트웨어마이스터고등학교 + + 1학년 + + 여자 + + + 내보내기 + + ))} + + } + + {modal && setModal(false)} postId={1} />} + + ); +}; + +export default DetailPost; diff --git a/src/components/My/DetailPost/style.ts b/src/components/My/DetailPost/style.ts new file mode 100644 index 0000000..9eb5e50 --- /dev/null +++ b/src/components/My/DetailPost/style.ts @@ -0,0 +1,142 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + padding: 1.75rem 1.5rem; + max-width: 37.5rem; + width: 100%; + display: flex; + flex-direction: column; + gap: 2.5rem; + border: 1px solid ${({ theme }) => theme.color.gray[100]}; + border-radius: 0.5rem; +`; + +export const PostContainer = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 1.75rem; +`; + +export const ApplyContainer = styled.div` + display: flex; + flex-direction: column; + gap: 20px; +`; + +export const PostText = styled.div` + display: flex; + flex-direction: column; + gap: 8px; +`; + +export const Title = styled.div` + ${({ theme }) => theme.fontStyle.h4.semi} + color: ${({ theme }) => theme.color.black}; +`; + +export const Content = styled.div` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.black}; +`; + +export const SNSContainer = styled.div` + display: flex; + flex-direction: column; + gap: 0.25rem; +`; + +export const SNSText = styled(Content)``; + +export const Deadline = styled(Content)``; + +export const PostData = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + gap: 1rem; +`; + +export const Remain = styled.span` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const TagReportContainer = styled.div` + display: flex; + justify-content: space-between; +`; + +export const ReportButton = styled.div` + cursor: pointer; +`; + +export const EditButton = styled.button` + ${({ theme }) => theme.fontStyle.m3.semi}; + color: ${({ theme }) => theme.color.white}; + border: none; + border-radius: 0.5rem; + background: ${({ theme }) => theme.color.gray[600]}; + display: flex; + padding: 0.75rem 1.75rem; + justify-content: center; + align-items: center; + gap: 0.625rem; + cursor: pointer; +`; + +export const Line = styled.div` + background: ${({ theme }) => theme.color.gray[200]}; +`; + +export const ApplicantList = styled.div` + display: flex; + width: 600px; + flex-direction: column; + gap: 28px; +`; + +export const ApplicantContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +`; + +export const ProfileText = styled.div` + display: flex; + gap: 8px; +`; + +export const Name = styled.span` + ${({ theme }) => theme.fontStyle.m2.semi}; + color: ${({ theme }) => theme.color.black}; +`; + +export const Data = styled.div` + display: flex; + align-items: center; + gap: 0.25rem; +`; + +export const DataText = styled.span` + ${({ theme }) => theme.fontStyle.label}; + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const Dot = styled.div` + width: 0.25rem; + height: 0.25rem; + border-radius: 0.125rem; + background-color: #b4b5b7; +`; + +export const OutButton = styled.div` + display: flex; + padding: 8px 12px; + justify-content: center; + align-items: center; + gap: 10px; + border-radius: 8px; + background: ${({ theme }) => theme.color.system}; + color: ${({ theme }) => theme.color.white}; +`; diff --git a/src/components/My/PostList/PostCard/TagList/TagItem/index.tsx b/src/components/My/PostList/PostCard/TagList/TagItem/index.tsx new file mode 100644 index 0000000..dd77ba1 --- /dev/null +++ b/src/components/My/PostList/PostCard/TagList/TagItem/index.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import * as S from './style'; +import { tagType } from 'types/Card'; + +const TagItem = ({ tag }: { tag: tagType }) => { + const text = { + WALK: '산책', + WORRY: '고민', + CHAT: '잡담', + EXERCISE: '운동', + STUDY: '공부', + GO_OUT: '외출', + }; + return ( + + #{text[tag]} + + ); +}; + +export default TagItem; diff --git a/src/components/My/PostList/PostCard/TagList/TagItem/style.ts b/src/components/My/PostList/PostCard/TagList/TagItem/style.ts new file mode 100644 index 0000000..4330a1a --- /dev/null +++ b/src/components/My/PostList/PostCard/TagList/TagItem/style.ts @@ -0,0 +1,15 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + border: 1px solid #eff0f2; + border-radius: 8px; + display: flex; + padding: 4px 12px; + justify-content: center; + align-items: center; + gap: 10px; +`; + +export const Tag = styled.div` + color: #a5a6a9; +`; diff --git a/src/components/My/PostList/PostCard/TagList/index.tsx b/src/components/My/PostList/PostCard/TagList/index.tsx new file mode 100644 index 0000000..9a17486 --- /dev/null +++ b/src/components/My/PostList/PostCard/TagList/index.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import * as S from './style'; +import TagItem from './TagItem'; +import Card from 'types/Card'; + +const TagList = ({ tag }: Pick) => { + return ( + + {tag.map((item, index) => ( + + ))} + + ); +}; + +export default TagList; diff --git a/src/components/My/PostList/PostCard/TagList/style.ts b/src/components/My/PostList/PostCard/TagList/style.ts new file mode 100644 index 0000000..92be720 --- /dev/null +++ b/src/components/My/PostList/PostCard/TagList/style.ts @@ -0,0 +1,6 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + display: flex; + gap: 12px; +`; diff --git a/src/components/My/PostList/PostCard/index.tsx b/src/components/My/PostList/PostCard/index.tsx new file mode 100644 index 0000000..50012f3 --- /dev/null +++ b/src/components/My/PostList/PostCard/index.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import * as S from './style'; +import TagList from './TagList'; +import MateList from 'components/MateList'; +import Card from 'types/Card'; + +const PostCard = ({ + author, + author_gender, + author_grade, + author_school, + gender, + grade, + tag, + title, +}: Card) => { + const text: { [key: string]: string } = { + ONE: '1학년', + TWO: '2학년', + THREE: '3학년', + FOUR: '4학년', + FIVE: '5학년', + SIX: '6학년', + MALE: '남자', + FEMALE: '여자', + ANY: '성별무관', + }; + + return ( + + + + {author} + + + {author_school} + + {text[author_grade]} + + {text[author_gender]} + + + {title} + + + ); +}; + +export default PostCard; diff --git a/src/components/My/PostList/PostCard/style.ts b/src/components/My/PostList/PostCard/style.ts new file mode 100644 index 0000000..201e9a8 --- /dev/null +++ b/src/components/My/PostList/PostCard/style.ts @@ -0,0 +1,52 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + width: 550px; + padding: 1.25rem 1.5rem; + border-radius: 0.5rem; + border: 1px solid #f5f6f8; + display: flex; + flex-direction: column; + gap: 1rem; + background-color: white; +`; + +export const AuthorDataBox = styled.div` + display: flex; + align-items: center; + gap: 0.5rem; +`; + +export const Author = styled.div` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.gray[600]}; +`; + +export const Contour = styled.div` + width: 0.0625rem; + height: 1.25rem; + border-radius: 0.3125rem; + background: #d9d9d9; +`; + +export const AuthorData = styled.div` + display: flex; + align-items: center; + gap: 0.25rem; + span { + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.gray[400]}; + } +`; + +export const Dot = styled.div` + width: 4px; + height: 4px; + border-radius: 2px; + background-color: ${({ theme }) => theme.color.gray[400]}; +`; + +export const Title = styled.div` + ${({ theme }) => theme.fontStyle.m1.semi} + color: ${({ theme }) => theme.color.black}; +`; diff --git a/src/components/My/PostList/PostHeader/index.tsx b/src/components/My/PostList/PostHeader/index.tsx new file mode 100644 index 0000000..8a57250 --- /dev/null +++ b/src/components/My/PostList/PostHeader/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import * as S from './style'; + +const PostHeader = () => { + return ( + + 내가 작성한 글 + 신청한 예약 + + ); +}; + +export default PostHeader; diff --git a/src/components/My/PostList/PostHeader/style.ts b/src/components/My/PostList/PostHeader/style.ts new file mode 100644 index 0000000..55f44e8 --- /dev/null +++ b/src/components/My/PostList/PostHeader/style.ts @@ -0,0 +1,17 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + align-self: flex-start; + gap: 20px; +`; + +export const Text = styled.div<{ selected: boolean }>` + ${({ theme }) => theme.fontStyle.m3.semi}; + color: ${({ selected, theme }) => + selected ? theme.color.main : theme.color.black}; + border-bottom: ${({ selected, theme }) => + selected ? `1px solid ${theme.color.main} ` : '0'}; +`; diff --git a/src/components/My/PostList/index.tsx b/src/components/My/PostList/index.tsx new file mode 100644 index 0000000..6e9d0d4 --- /dev/null +++ b/src/components/My/PostList/index.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import * as S from './style'; +import PostHeader from './PostHeader'; +import PostCard from './PostCard'; +import { useNavigate } from 'react-router-dom'; + +const PostList = () => { + const navigate = useNavigate(); + + return ( + + + + {[...Array(8)].map((_, idx) => ( +
navigate('edit/1')}> + +
+ ))} +
+
+ ); +}; + +export default PostList; diff --git a/src/components/My/PostList/style.ts b/src/components/My/PostList/style.ts new file mode 100644 index 0000000..4a264fa --- /dev/null +++ b/src/components/My/PostList/style.ts @@ -0,0 +1,15 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + width: 600px; + display: inline-flex; + flex-direction: column; + gap: 20px; +`; + +export const List = styled.div` + width: 600px; + display: flex; + flex-direction: column; + gap: 16px; +`; diff --git a/src/components/My/Profile/Detail/index.tsx b/src/components/My/Profile/Detail/index.tsx new file mode 100644 index 0000000..a021d4f --- /dev/null +++ b/src/components/My/Profile/Detail/index.tsx @@ -0,0 +1,39 @@ +import React, { useState } from 'react'; +import * as S from './style'; +import KebabIcon from 'svg/KebabIcon'; +import Portal from 'components/Portal'; +import ImageChange from 'components/Modal/ImageChange'; + +const Detail = () => { + const [modal, setModal] = useState(false); + const [change, setChange] = useState(false); + + return ( + <> + + setModal(!modal)}> + + + {modal && ( + + { + setChange(true); + console.log(change); + }}> + 프로필 변경 + + 로그아웃 + + )} + + {change && ( + + setChange(false)} /> + + )} + + ); +}; + +export default Detail; diff --git a/src/components/My/Profile/Detail/style.ts b/src/components/My/Profile/Detail/style.ts new file mode 100644 index 0000000..5d039d7 --- /dev/null +++ b/src/components/My/Profile/Detail/style.ts @@ -0,0 +1,30 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + position: relative; +`; + +export const Button = styled.div``; + +export const DetailModal = styled.div` + position: absolute; + left: -118px; + display: inline-flex; + padding: 24px; + flex-direction: column; + align-items: flex-start; + gap: 32px; + border-radius: 8px; + background: ${({ theme }) => theme.color.white}; + box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.08); +`; + +export const Text = styled.div` + ${({ theme }) => theme.fontStyle.m3.reg} + color: ${({ theme }) => theme.color.black}; + cursor: pointer; +`; + +export const WarningText = styled(Text)` + color: ${({ theme }) => theme.color.system}; +`; diff --git a/src/components/My/Profile/UserData/index.tsx b/src/components/My/Profile/UserData/index.tsx new file mode 100644 index 0000000..eef489c --- /dev/null +++ b/src/components/My/Profile/UserData/index.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import * as S from './style'; + +const UserData = () => { + return ( + + + + 한재형 + + 광주소프트웨어마이스터고등학교 + + 1학년 + + 여자 + + + + ); +}; + +export default UserData; diff --git a/src/components/My/Profile/UserData/style.ts b/src/components/My/Profile/UserData/style.ts new file mode 100644 index 0000000..bcbdd96 --- /dev/null +++ b/src/components/My/Profile/UserData/style.ts @@ -0,0 +1,43 @@ +import styled from '@emotion/styled'; + +export const Wrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + gap: 12px; +`; + +export const Profile = styled.img` + width: 3rem; + height: 3rem; + border-radius: 100%; +`; + +export const Text = styled.div` + display: flex; + flex-direction: column; + justify-content: center; +`; + +export const Name = styled.span` + ${({ theme }) => theme.fontStyle.m3}; + color: ${({ theme }) => theme.color.black}; +`; + +export const Data = styled.div` + display: flex; + align-items: center; + gap: 0.25rem; +`; + +export const DataText = styled.span` + ${({ theme }) => theme.fontStyle.label}; + color: ${({ theme }) => theme.color.gray[500]}; +`; + +export const Dot = styled.div` + width: 0.25rem; + height: 0.25rem; + border-radius: 0.125rem; + background-color: #b4b5b7; +`; diff --git a/src/components/My/Profile/index.tsx b/src/components/My/Profile/index.tsx new file mode 100644 index 0000000..8c9be12 --- /dev/null +++ b/src/components/My/Profile/index.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import * as S from './style'; +import UserData from './UserData'; +import Detail from './Detail'; + +const Profile = () => { + return ( + + + + + ); +}; + +export default Profile; diff --git a/src/components/My/Profile/style.ts b/src/components/My/Profile/style.ts new file mode 100644 index 0000000..96f0a5e --- /dev/null +++ b/src/components/My/Profile/style.ts @@ -0,0 +1,8 @@ +import styled from '@emotion/styled'; + +export const Postioner = styled.div` + width: 600px; + display: flex; + justify-content: space-between; + align-items: center; +`; diff --git a/src/components/Portal/index.tsx b/src/components/Portal/index.tsx index 24bc186..d89f298 100644 --- a/src/components/Portal/index.tsx +++ b/src/components/Portal/index.tsx @@ -10,10 +10,9 @@ import * as S from './style'; interface Props { children: ReactElement; - onClose?: () => void; } -const Portal = ({ children, onClose }: Props) => { +const Portal = ({ children }: Props) => { const [mounted, setMounted] = useState(false); const portal = document.getElementById('modal'); @@ -31,9 +30,7 @@ const Portal = ({ children, onClose }: Props) => { return mounted ? ( ReactDOM.createPortal( - - {cloneElement(children, { onClick })} - , + {cloneElement(children, { onClick })}, portal, ) ) : ( diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index 24baa89..a16f319 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -1,7 +1,11 @@ import React, { useState } from 'react'; -import { PostList, Filter, Location, Header, Banner } from 'components'; -import { FilterIcon } from 'svg'; +import PostList from 'components/Post/PostList'; +import { Filter } from 'components/Filter'; import * as S from './style'; +import Location from 'components/Location'; +import Header from 'components/Header'; +import Banner from 'components/Banner'; +import { FilterIcon } from 'svg/index'; const Home = () => { const [modal, setModal] = useState(false); @@ -12,17 +16,19 @@ const Home = () => { - - - - setModal(true)}> - - 필터 - - {modal && setModal(false)} />} - - - + + + + + setModal(true)}> + + 필터 + + {modal && setModal(false)} />} + + + + diff --git a/src/pages/my/cancle/index.tsx b/src/pages/my/cancle/index.tsx new file mode 100644 index 0000000..fc7d40c --- /dev/null +++ b/src/pages/my/cancle/index.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import * as S from './style'; +import Header from 'components/Header'; +import CanclePage from 'components/My/CanclePage'; + +const Cancle = () => { + return ( + +
+ + + + + ); +}; + +export default Cancle; diff --git a/src/pages/my/cancle/style.ts b/src/pages/my/cancle/style.ts new file mode 100644 index 0000000..9f6fa33 --- /dev/null +++ b/src/pages/my/cancle/style.ts @@ -0,0 +1,14 @@ +import styled from '@emotion/styled'; + +export const Postioner = styled.div` + display: flex; + flex-direction: column; + align-items: center; +`; + +export const Wrapper = styled.div` + padding-bottom: 57px; + display: flex; + flex-direction: column; + align-items: center; +`; diff --git a/src/pages/my/edit/index.tsx b/src/pages/my/edit/index.tsx new file mode 100644 index 0000000..db1ba17 --- /dev/null +++ b/src/pages/my/edit/index.tsx @@ -0,0 +1,17 @@ +import DetailPost from 'components/My/DetailPost'; +import React from 'react'; +import * as S from './style'; +import Header from 'components/Header'; + +const Edit = () => { + return ( + +
+ + + + + ); +}; + +export default Edit; diff --git a/src/pages/my/edit/style.ts b/src/pages/my/edit/style.ts new file mode 100644 index 0000000..9f6fa33 --- /dev/null +++ b/src/pages/my/edit/style.ts @@ -0,0 +1,14 @@ +import styled from '@emotion/styled'; + +export const Postioner = styled.div` + display: flex; + flex-direction: column; + align-items: center; +`; + +export const Wrapper = styled.div` + padding-bottom: 57px; + display: flex; + flex-direction: column; + align-items: center; +`; diff --git a/src/pages/my/index.tsx b/src/pages/my/index.tsx new file mode 100644 index 0000000..c2cacc6 --- /dev/null +++ b/src/pages/my/index.tsx @@ -0,0 +1,19 @@ +import Profile from 'components/My/Profile'; +import React from 'react'; +import * as S from './style'; +import Header from 'components/Header'; +import PostList from 'components/My/PostList'; + +const My = () => { + return ( + +
+ + + + + + ); +}; + +export default My; diff --git a/src/pages/my/style.ts b/src/pages/my/style.ts new file mode 100644 index 0000000..61251b1 --- /dev/null +++ b/src/pages/my/style.ts @@ -0,0 +1,15 @@ +import styled from '@emotion/styled'; + +export const Postioner = styled.div` + display: flex; + flex-direction: column; + align-items: center; + gap: 40px; +`; + +export const Wrapper = styled.div` + display: flex; + flex-direction: column; + align-items: center; + gap: 28px; +`; diff --git a/src/svg/ChangeIcon.tsx b/src/svg/ChangeIcon.tsx new file mode 100644 index 0000000..cf0fbd5 --- /dev/null +++ b/src/svg/ChangeIcon.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +const ChangeIcon = () => { + return ( + + + + + + + ); +}; + +export default ChangeIcon; diff --git a/src/svg/KebabIcon.tsx b/src/svg/KebabIcon.tsx new file mode 100644 index 0000000..d95c584 --- /dev/null +++ b/src/svg/KebabIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +const KebabIcon = () => { + return ( + + + + + + ); +}; + +export default KebabIcon;