-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #68 from KDT-Web-IDE-Project/67-feat
feat: 마이페이지 UI 구현
- Loading branch information
Showing
2 changed files
with
376 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
`; |