Skip to content

Commit

Permalink
feat: (#18) 게시글에서 보는 투표 선택지 컴포넌트 UI 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
Gilpop8663 committed Jul 11, 2023
1 parent d7fe8dc commit 4381f6e
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 Select: Story = {
render: () => <ProgressBar percent={20} isSelect={true} />,
};

export const NotSelect: Story = {
render: () => <ProgressBar percent={20} isSelect={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;
isSelect: boolean;
}

export default function ProgressBar({ percent, isSelect }: ProgressBarProps) {
return (
<S.Container>
<S.Bar progress={`${percent}%`} isSelect={isSelect} />
</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: string; isSelect: boolean }>`
border-radius: 4px;
width: ${({ progress }) => progress};
height: 8px;
background-color: ${({ isSelect }) => (isSelect ? '#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
onClick={() => {}}
isPreview={true}
text="자유를 찾게 냅둔다"
peopleCount={2}
percent={20}
isSelect={true}
isVote={true}
/>
</WrittenVoteWrapper>
),
};

export const NotSelectAndLongText: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={true}
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를"
percent={80}
peopleCount={6}
isSelect={false}
isVote={true}
/>
</WrittenVoteWrapper>
),
};

export const ImageAndSelect: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={true}
imageUrl="https://source.unsplash.com/random"
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를"
percent={80}
peopleCount={6}
isSelect={true}
isVote={true}
/>
</WrittenVoteWrapper>
),
};

export const NotVote: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={true}
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를"
percent={0}
peopleCount={0}
isSelect={false}
isVote={false}
/>
</WrittenVoteWrapper>
),
};

export const ImageAndNotVote: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={true}
imageUrl="https://source.unsplash.com/random"
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를"
percent={0}
peopleCount={0}
isSelect={false}
isVote={false}
/>
</WrittenVoteWrapper>
),
};

export const PreviewContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={true}
imageUrl="https://source.unsplash.com/random"
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다."
percent={0}
peopleCount={0}
isSelect={false}
isVote={false}
/>
</WrittenVoteWrapper>
),
};

export const DetailContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={false}
imageUrl="https://source.unsplash.com/random"
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다."
percent={0}
peopleCount={0}
isSelect={false}
isVote={false}
/>
</WrittenVoteWrapper>
),
};

export const NoImageAndDetailContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={false}
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다."
percent={60}
peopleCount={8}
isSelect={true}
isVote={true}
/>
</WrittenVoteWrapper>
),
};

export const ImageAndSelectAndDetailContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
onClick={() => {}}
isPreview={false}
imageUrl="https://source.unsplash.com/random"
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다."
percent={60}
peopleCount={8}
isSelect={true}
isVote={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 {
onClick: () => void;
text: string;
isVote: boolean;
peopleCount: number;
percent: number;
isSelect: boolean;
isPreview: boolean;
imageUrl?: string;
}

export default function WrittenVoteOption({
onClick,
text,
isVote,
peopleCount,
percent,
isSelect,
isPreview,
imageUrl,
}: WrittenVoteOptionProps) {
return (
<S.Container aria-label={text} isSelect={isSelect} onClick={onClick}>
{imageUrl && <S.Image src={imageUrl} alt={text} />}
{isPreview ? (
<S.PreviewContent>{text}</S.PreviewContent>
) : (
<S.DetailContent>{text}</S.DetailContent>
)}
{isVote && (
<>
<S.ProgressContainer>
<ProgressBar percent={percent} isSelect={isSelect} />
</S.ProgressContainer>
<S.TextContainer>
<S.PeopleText>{peopleCount}</S.PeopleText>
<S.PercentText>({percent.toFixed(0)}%)</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<{ isSelect: boolean }>`
display: flex;
flex-direction: column;
border: ${({ isSelect }) => (isSelect ? '2px solid #ff7877' : '1px solid rgba(0, 0, 0, 0.1)')};
border-radius: 4px;
padding: 15px 20px;
background: #f6f6f6;
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.span`
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.span`
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 4381f6e

Please sign in to comment.