-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: (#18) 게시글에서 보는 투표 선택지 컴포넌트 UI 구현 * refactor: (#18) 가독성 좋은 코드가 되도록 변수명 수정 및 CSS 속성 변경 글 목록에서 이미지 안 보이도록 수정 * refactor: (#18) 불필요한 코드 삭제 및 퍼센트 소수점 1자리 보이도록 수정
- Loading branch information
1 parent
3cc6985
commit ad5f459
Showing
9 changed files
with
553 additions
and
0 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
...ts/optionList/WrittenVoteOptionList/WrittenVoteOption/ProgressBar/ProgressBar.stories.tsx
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,18 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import ProgressBar from '.'; | ||
|
||
const meta: Meta<typeof ProgressBar> = { | ||
component: ProgressBar, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof ProgressBar>; | ||
|
||
export const Selected: Story = { | ||
render: () => <ProgressBar percent={20} isSelected={true} />, | ||
}; | ||
|
||
export const NotSelected: Story = { | ||
render: () => <ProgressBar percent={20} isSelected={false} />, | ||
}; |
16 changes: 16 additions & 0 deletions
16
...d/src/components/optionList/WrittenVoteOptionList/WrittenVoteOption/ProgressBar/index.tsx
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,16 @@ | ||
import React from 'react'; | ||
|
||
import * as S from './style'; | ||
|
||
interface ProgressBarProps { | ||
percent: number; | ||
isSelected: boolean; | ||
} | ||
|
||
export default function ProgressBar({ percent, isSelected }: ProgressBarProps) { | ||
return ( | ||
<S.Container> | ||
<S.Bar progress={percent} isSelected={isSelected} /> | ||
</S.Container> | ||
); | ||
} |
18 changes: 18 additions & 0 deletions
18
...nd/src/components/optionList/WrittenVoteOptionList/WrittenVoteOption/ProgressBar/style.ts
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,18 @@ | ||
import { styled } from 'styled-components'; | ||
|
||
export const Container = styled.div` | ||
border-radius: 4px; | ||
height: 8px; | ||
background-color: rgba(0, 0, 0, 0.3); | ||
`; | ||
|
||
export const Bar = styled.div<{ progress: number; isSelected: boolean }>` | ||
border-radius: 4px; | ||
width: ${({ progress }) => `${progress}%`}; | ||
height: 8px; | ||
background-color: ${({ isSelected }) => (isSelected ? '#ff7877' : '#9F9F9F')}; | ||
`; |
165 changes: 165 additions & 0 deletions
165
...mponents/optionList/WrittenVoteOptionList/WrittenVoteOption/WrittenVoteOption.stories.tsx
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,165 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { styled } from 'styled-components'; | ||
|
||
import WrittenVoteOption from '.'; | ||
|
||
const meta: Meta<typeof WrittenVoteOption> = { | ||
component: WrittenVoteOption, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof WrittenVoteOption>; | ||
|
||
const WrittenVoteWrapper = styled.div` | ||
max-width: 460px; | ||
`; | ||
|
||
export const Select: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={true} | ||
text="자유를 찾게 냅둔다" | ||
peopleCount={2} | ||
percent={70.9} | ||
isSelected={true} | ||
isVoted={true} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const NotSelectAndLongText: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={true} | ||
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를" | ||
percent={80} | ||
peopleCount={6} | ||
isSelected={false} | ||
isVoted={true} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const ImageAndSelect: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={true} | ||
imageUrl="https://source.unsplash.com/random" | ||
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를" | ||
percent={80} | ||
peopleCount={6} | ||
isSelected={true} | ||
isVoted={true} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const NotVote: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={true} | ||
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를" | ||
percent={0} | ||
peopleCount={0} | ||
isSelected={false} | ||
isVoted={false} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const ImageAndNotVote: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={true} | ||
imageUrl="https://source.unsplash.com/random" | ||
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를" | ||
percent={0} | ||
peopleCount={0} | ||
isSelected={false} | ||
isVoted={false} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const PreviewContent: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={true} | ||
imageUrl="https://source.unsplash.com/random" | ||
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다." | ||
percent={0} | ||
peopleCount={0} | ||
isSelected={false} | ||
isVoted={false} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const DetailContent: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={false} | ||
imageUrl="https://source.unsplash.com/random" | ||
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다." | ||
percent={0} | ||
peopleCount={0} | ||
isSelected={false} | ||
isVoted={false} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const NoImageAndDetailContent: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={false} | ||
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다." | ||
percent={60} | ||
peopleCount={8} | ||
isSelected={true} | ||
isVoted={true} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; | ||
|
||
export const ImageAndSelectAndDetailContent: Story = { | ||
render: () => ( | ||
<WrittenVoteWrapper> | ||
<WrittenVoteOption | ||
handleVoteClick={() => {}} | ||
isPreview={false} | ||
imageUrl="https://source.unsplash.com/random" | ||
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다." | ||
percent={60} | ||
peopleCount={8} | ||
isSelected={true} | ||
isVoted={true} | ||
/> | ||
</WrittenVoteWrapper> | ||
), | ||
}; |
48 changes: 48 additions & 0 deletions
48
frontend/src/components/optionList/WrittenVoteOptionList/WrittenVoteOption/index.tsx
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,48 @@ | ||
import React from 'react'; | ||
|
||
import ProgressBar from './ProgressBar'; | ||
import * as S from './style'; | ||
|
||
interface WrittenVoteOptionProps { | ||
handleVoteClick: () => void; | ||
text: string; | ||
isVoted: boolean; | ||
peopleCount: number; | ||
percent: number; | ||
isSelected: boolean; | ||
isPreview: boolean; | ||
imageUrl?: string; | ||
} | ||
|
||
export default function WrittenVoteOption({ | ||
handleVoteClick, | ||
text, | ||
isVoted, | ||
peopleCount, | ||
percent, | ||
isSelected, | ||
isPreview, | ||
imageUrl, | ||
}: WrittenVoteOptionProps) { | ||
return ( | ||
<S.Container isSelected={isSelected} onClick={handleVoteClick}> | ||
{!isPreview && imageUrl && <S.Image src={imageUrl} alt={text} />} | ||
{isPreview ? ( | ||
<S.PreviewContent>{text}</S.PreviewContent> | ||
) : ( | ||
<S.DetailContent>{text}</S.DetailContent> | ||
)} | ||
{isVoted && ( | ||
<> | ||
<S.ProgressContainer> | ||
<ProgressBar percent={percent} isSelected={isSelected} /> | ||
</S.ProgressContainer> | ||
<S.TextContainer> | ||
<S.PeopleText>{peopleCount}명</S.PeopleText> | ||
<S.PercentText>({percent.toFixed(1)}%)</S.PercentText> | ||
</S.TextContainer> | ||
</> | ||
)} | ||
</S.Container> | ||
); | ||
} |
100 changes: 100 additions & 0 deletions
100
frontend/src/components/optionList/WrittenVoteOptionList/WrittenVoteOption/style.ts
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,100 @@ | ||
import { styled } from 'styled-components'; | ||
|
||
export const Container = styled.li<{ isSelected: boolean }>` | ||
display: flex; | ||
flex-direction: column; | ||
border: ${({ isSelected }) => | ||
isSelected ? '2px solid #ff7877' : '1px solid rgba(0, 0, 0, 0.1)'}; | ||
border-radius: 4px; | ||
padding: 15px 20px; | ||
color: #5b5b5b; | ||
cursor: pointer; | ||
@media (min-width: 960px) { | ||
padding: 20px 30px; | ||
} | ||
`; | ||
|
||
export const Image = styled.img` | ||
border-radius: 4px; | ||
margin-bottom: 12px; | ||
width: 100%; | ||
aspect-ratio: 1/1; | ||
object-fit: cover; | ||
@media (min-width: 960px) { | ||
margin-bottom: 24px; | ||
} | ||
`; | ||
|
||
export const PreviewContent = styled.p` | ||
display: -webkit-box; | ||
font-size: 1.4rem; | ||
font-weight: 500; | ||
text-overflow: ellipsis; | ||
word-break: break-word; | ||
overflow: hidden; | ||
-webkit-line-clamp: 2; // 원하는 라인수 | ||
-webkit-box-orient: vertical; | ||
@media (min-width: 960px) { | ||
font-size: 1.6rem; | ||
} | ||
`; | ||
|
||
export const DetailContent = styled.p` | ||
font-size: 1.4rem; | ||
font-weight: 500; | ||
@media (min-width: 960px) { | ||
font-size: 1.6rem; | ||
} | ||
`; | ||
|
||
export const ProgressContainer = styled.div` | ||
margin-top: 12px; | ||
@media (min-width: 960px) { | ||
margin-top: 18px; | ||
} | ||
`; | ||
|
||
export const TextContainer = styled.div` | ||
margin-top: 8px; | ||
text-align: end; | ||
font-weight: 500; | ||
@media (min-width: 960px) { | ||
margin-top: 12px; | ||
font-size: 1.6rem; | ||
} | ||
`; | ||
|
||
export const PeopleText = styled.span` | ||
font-size: 1.4rem; | ||
@media (min-width: 960px) { | ||
font-size: 1.6rem; | ||
} | ||
`; | ||
|
||
export const PercentText = styled.span` | ||
margin-left: 4px; | ||
font-size: 1.2rem; | ||
opacity: 0.7; | ||
@media (min-width: 960px) { | ||
font-size: 1.4rem; | ||
} | ||
`; |
Oops, something went wrong.