Skip to content

Commit

Permalink
Merge pull request #68 from KDT-Web-IDE-Project/67-feat
Browse files Browse the repository at this point in the history
feat: 마이페이지 UI 구현
  • Loading branch information
seungwoohan12 authored Jan 27, 2025
2 parents fc05505 + 0958654 commit 9ce2a06
Show file tree
Hide file tree
Showing 2 changed files with 376 additions and 6 deletions.
153 changes: 147 additions & 6 deletions src/pages/MyPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,150 @@
import React from 'react'
import React, { useState } from 'react';
import defaultImg from '../../assets/icons/logo_black.svg';
import {
BsImageFill,
BsPencilFill,
BsFillCheckCircleFill,
} from 'react-icons/bs';
import { Input } from '../../components/common/Input';
import {
EditInfo,
MyPageContainer,
MyPageContent,
MyPageHeader,
MyPageHeaderUserName,
ProfileImage,
ProfileInfo,
ProfileInfoDetails,
ProfileInfoDetailsContent,
RadioOption,
ThemeSelectionForm,
ThemeSelectionSection,
UncheckedCircle,
UserInfoSection,
} from './style';

const MyPage: React.FC = () => {
const userName = '유지희';
const userId = 'esder1310';

const [isEditingId, setIsEditingId] = useState(false);
const [isEditingName, setIsEditingName] = useState(false);
const [selectedTheme, setSelectedTheme] = useState('dark');

const handleThemeChange = (theme: string) => {
setSelectedTheme(theme);
};

const MyPage:React.FC = () => {
return (
<div>MyPage</div>
)
}
<MyPageContainer>
<MyPageHeader>
<MyPageHeaderUserName>{userName}</MyPageHeaderUserName>님의 마이페이지
</MyPageHeader>

<MyPageContent>
<UserInfoSection aria-labelledby="user-info">
<h2 id="user-info" style={{ display: 'none' }}>
사용자 정보
</h2>

<ProfileImage>
<img src={defaultImg} alt="프로필 이미지" />
<button aria-label="프로필 이미지 수정">
<BsImageFill className="icon_image" />
</button>
</ProfileImage>

<ProfileInfo>
<ProfileInfoDetails>
<label htmlFor="id">
| 사용자 아이디
<button
onClick={() => setIsEditingId(true)}
aria-label="사용자 아이디 수정"
>
<BsPencilFill className="icon_edit" />
</button>
</label>
{isEditingId ? (
<EditInfo>
<Input
type="id"
id="id"
value={userId}
onChange={() => {}}
placeholder="수정할 아이디를 입력하세요."
/>
<button onClick={() => setIsEditingId(false)}>
수정완료
</button>
</EditInfo>
) : (
<ProfileInfoDetailsContent>{userId}</ProfileInfoDetailsContent>
)}
</ProfileInfoDetails>

<ProfileInfoDetails>
<label htmlFor="name">
| 사용자 이름
<button
onClick={() => setIsEditingName(true)}
aria-label="사용자 이름 수정"
>
<BsPencilFill className="icon_edit" />
</button>
</label>
{isEditingName ? (
<EditInfo>
<Input
type="text"
id="name"
value={userName}
onChange={() => {}}
placeholder="수정할 이름 입력하세요."
/>
<button onClick={() => setIsEditingName(false)}>
수정완료
</button>
</EditInfo>
) : (
<ProfileInfoDetailsContent>
{userName}
</ProfileInfoDetailsContent>
)}
</ProfileInfoDetails>
</ProfileInfo>
</UserInfoSection>

<ThemeSelectionSection aria-labelledby="theme-selection">
<h2 id="theme-selection">테마 선택</h2>
<ThemeSelectionForm action="">
<RadioOption
isChecked={selectedTheme === 'dark'}
onClick={() => handleThemeChange('dark')}
>
{selectedTheme === 'dark' ? (
<BsFillCheckCircleFill size="1.5rem" />
) : (
<UncheckedCircle />
)}
<label>Dark Mode</label>
</RadioOption>
<RadioOption
isChecked={selectedTheme === 'light'}
onClick={() => handleThemeChange('light')}
>
{selectedTheme === 'light' ? (
<BsFillCheckCircleFill size="1.5rem" />
) : (
<UncheckedCircle />
)}
<label>Light Mode</label>
</RadioOption>
</ThemeSelectionForm>
</ThemeSelectionSection>
</MyPageContent>
</MyPageContainer>
);
};

export default MyPage
export default MyPage;
229 changes: 229 additions & 0 deletions src/pages/MyPage/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import styled from '@emotion/styled';

export const MyPageContainer = styled.div`
display: flex;
flex-direction: column;
gap: 2.25rem;
width: auto;
height: 100vh;
box-sizing: border-box;
padding: 1.81rem 3rem 2.31rem 3.38rem;
`;

export const MyPageHeader = styled.header`
color: #fff;
text-shadow: 0px 0px 4px var(--black);
font-family: 'Pretendard';
font-size: 2.5rem;
font-style: normal;
font-weight: 700;
line-height: normal;
`;

export const MyPageHeaderUserName = styled.span`
font-size: 4.0625rem;
`;

export const MyPageContent = styled.div`
border-radius: 2.1875rem;
background: var(--container);
height: 100%;
display: flex;
flex-direction: column;
gap: 1.81rem;
padding: 2.06rem;
`;

export const UserInfoSection = styled.section`
display: flex;
gap: 2.56rem;
`;

export const ProfileImage = styled.div`
width: 21.875rem;
height: 21.875rem;
border-radius: 1.0625rem;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
button {
width: 2.5rem;
height: 2.5rem;
border-radius: 0.4375rem;
background: var(--gray);
border: none;
position: absolute;
top: 18.25rem;
right: 1.13rem;
z-index: 2;
display: flex;
justify-content: center;
align-items: center;
.icon_image {
width: 1.5rem;
height: 1.5rem;
}
}
`;

export const ProfileInfo = styled.div`
display: flex;
flex-direction: column;
gap: 2.69rem;
`;

export const ProfileInfoDetails = styled.div`
display: flex;
flex-direction: column;
gap: 1.5rem;
label {
color: var(--light-gray);
font-family: 'Pretendard';
font-size: 1.375rem;
font-style: normal;
font-weight: 600;
line-height: normal;
letter-spacing: -0.06875rem;
display: flex;
align-items: center;
gap: 1rem;
button {
background: none;
border: none;
cursor: pointer;
.icon_edit {
width: 1.5rem;
height: 1.5rem;
}
}
}
`;

export const EditInfo = styled.div`
display: flex;
gap: 1.88rem;
align-items: center;
button {
width: 5.75rem;
height: 3.4375rem;
border: none;
border-radius: 1.0625rem;
background: var(--gray, #5a5a5a);
cursor: pointer;
color: var(--white, #fff);
font-family: 'Pretendard';
font-size: 1.25rem;
font-style: normal;
font-weight: 700;
line-height: normal;
letter-spacing: -0.025rem;
&:hover {
background: var(--light-gray);
color: var(--background);
}
}
`;

export const ProfileInfoDetailsContent = styled.div`
color: #fff;
font-family: 'Pretendard';
font-size: 1.625rem;
font-style: normal;
font-weight: 500;
line-height: normal;
`;

export const ThemeSelectionSection = styled.section`
width: 21.875rem;
height: 11.4375rem;
border-radius: 1.0625rem;
background: var(--gray);
padding: 1.25rem 1.31rem;
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 0.88rem;
h2 {
color: var(--white);
font-family: 'Pretendard Variable';
font-size: 1.5625rem;
font-style: normal;
font-weight: 700;
line-height: normal;
}
`;

export const ThemeSelectionForm = styled.form`
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
div {
height: 2.8125rem;
display: flex;
gap: 0.94rem;
align-items: center;
border-radius: 0.4375rem;
&.selected {
background: var(--input);
}
input[type='radio'] {
accent-color: var(--white);
}
label {
color: var(--white);
font-family: 'Pretendard Variable';
font-size: 1.25rem;
font-style: normal;
font-weight: 700;
line-height: normal;
}
}
`;

export const RadioOption = styled.div<{ isChecked: boolean }>`
height: 2.8125rem;
display: flex;
align-items: center;
gap: 0.94rem;
cursor: pointer;
padding: 0.69rem;
box-sizing: border-box;
border-radius: 0.4375rem;
background-color: ${(props) =>
props.isChecked ? 'var(--input)' : 'transparent'};
label {
color: var(--white);
font-family: 'Pretendard Variable';
font-size: 1.25rem;
font-style: normal;
font-weight: 700;
line-height: normal;
}
`;

export const UncheckedCircle = styled.span`
width: 1.5rem;
height: 1.5rem;
border-radius: 50%;
background-color: var(--input, rgba(218, 218, 218, 0.35));
`;

0 comments on commit 9ce2a06

Please sign in to comment.