Skip to content

Commit

Permalink
게시글에서 보는 투표 선택지 컴포넌트 UI 구현 (#30)
Browse files Browse the repository at this point in the history
* feat: (#18) 게시글에서 보는 투표 선택지 컴포넌트 UI 구현

* refactor: (#18) 가독성 좋은 코드가 되도록 변수명 수정 및 CSS 속성 변경
글 목록에서 이미지 안 보이도록 수정

* refactor: (#18) 불필요한 코드 삭제 및 퍼센트 소수점 1자리 보이도록 수정
  • Loading branch information
Gilpop8663 authored Jul 12, 2023
1 parent 3cc6985 commit ad5f459
Show file tree
Hide file tree
Showing 9 changed files with 553 additions and 0 deletions.
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} />,
};
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>
);
}
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')};
`;
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>
),
};
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>
);
}
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;
}
`;
Loading

0 comments on commit ad5f459

Please sign in to comment.