Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

핵심 기능 웹 접근성 개선하기_Feat/#203 #222

Merged
merged 3 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions frontend/src/components/common/Post/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MouseEvent } from 'react';

import { PostInfo } from '@type/post';

import { changeVotedOption, votePost } from '@api/post';
Expand Down Expand Up @@ -31,19 +33,37 @@ export default function Post({ postInfo, isPreview }: PostProps) {
});
};

const handleLinkClick = (e: MouseEvent<HTMLAnchorElement>) => {
if (!isPreview) e.preventDefault();
};

return (
<S.Container>
<S.DetailLink to={`${PATH.POST}/${postId}`} $isPreview={isPreview}>
<S.Category>{category?.map(category => category.name).join(' | ')}</S.Category>
<S.Title $isPreview={isPreview}>{title}</S.Title>
<S.DetailLink
to={isPreview ? `${PATH.POST}/${postId}` : '#'}
$isPreview={isPreview}
onClick={handleLinkClick}
aria-describedby={
isPreview ? '해당 게시물의 상세페이지로 이동하기' : '현재 상세페이지이므로 사용할 수 없음'
}
aria-disabled={isPreview ? false : true}
>
<S.Category aria-label="카테고리">
{category.map(category => category.name).join(' | ')}
</S.Category>
<S.Title aria-label="제목" $isPreview={isPreview}>
{title}
</S.Title>
<S.Wrapper>
<span>{writer.nickname}</span>
<span aria-label="작성자">{writer.nickname}</span>
<S.Wrapper>
<span>{createTime}</span>
<span>{deadline}</span>
<span aria-label="작성일시">{startTime}</span>
<span aria-label="투표 마감일시">{endTime}</span>
</S.Wrapper>
</S.Wrapper>
<S.Content $isPreview={isPreview}>{content}</S.Content>
<S.Content aria-label="내용" $isPreview={isPreview}>
{content}
</S.Content>
</S.DetailLink>
<WrittenVoteOptionList
selectedOptionId={voteInfo.selectedOptionId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const Select: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={true}
text="자유를 찾게 냅둔다"
Expand All @@ -36,6 +37,7 @@ export const NotSelectAndLongText: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={true}
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를"
Expand All @@ -53,6 +55,7 @@ export const ImageAndSelect: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={true}
imageUrl="https://source.unsplash.com/random"
Expand All @@ -70,6 +73,7 @@ export const NotVote: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={true}
text="또는 JavaScript로 컴포넌트의 텍스트를 가져와서 원하는 길이로 자르고, 생략 부호를"
Expand All @@ -87,6 +91,7 @@ export const ImageAndNotVote: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={true}
imageUrl="https://source.unsplash.com/random"
Expand All @@ -104,6 +109,7 @@ export const PreviewContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={true}
imageUrl="https://source.unsplash.com/random"
Expand All @@ -121,6 +127,7 @@ export const DetailContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={false}
imageUrl="https://source.unsplash.com/random"
Expand All @@ -138,6 +145,7 @@ export const NoImageAndDetailContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={false}
text="isVote는 변수명으로서는 영문법상으로 볼 때는 어색하진 않습니다. is는 보통 boolean 타입을 나타낼 때 사용되는 접두사이며, Vote는 투표를 의미하는 명사입니다. 따라서 isVote는 투표 여부를 나타내는지를 의미하는 변수명으로 적합합니다. 그러나 개인적인 취향에 따라 다른 변수명을 선호할 수도 있습니다. 예를 들면 hasVoted와 같이 투표를 했는지 여부를 나타내는 변수명을 사용하는 것도 가능합니다. 중요한 것은 코드의 가독성과 일관성을 유지하는 것이며, 개발자들과의 커뮤니케이션을 원활하게 하기 위해 명확하고 이해하기 쉬운 변수명을 선택하는 것이 좋습니다."
Expand All @@ -155,6 +163,7 @@ export const ImageAndSelectAndDetailContent: Story = {
render: () => (
<WrittenVoteWrapper>
<WrittenVoteOption
ariaLabel="0번 선택지"
handleVoteClick={() => {}}
isPreview={false}
imageUrl="https://source.unsplash.com/random"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import React from 'react';

import ProgressBar from './ProgressBar';
import * as S from './style';

Expand All @@ -12,6 +10,7 @@ interface WrittenVoteOptionProps {
isSelected: boolean;
isPreview: boolean;
imageUrl: string;
ariaLabel: string;
}

export default function WrittenVoteOption({
Expand All @@ -23,23 +22,30 @@ export default function WrittenVoteOption({
isSelected,
isPreview,
imageUrl,
ariaLabel,
}: WrittenVoteOptionProps) {
return (
<S.Container $isSelected={isSelected} onClick={handleVoteClick}>
<S.Container
aria-label={`${ariaLabel}${isSelected ? ' 선택된 선택지' : ''}`}
$isSelected={isSelected}
onClick={handleVoteClick}
>
{!isPreview && imageUrl && <S.Image src={imageUrl} alt={text} />}
{isPreview ? (
<S.PreviewContent>{text}</S.PreviewContent>
<S.PreviewContent aria-label="선택지 내용">{text}</S.PreviewContent>
) : (
<S.DetailContent>{text}</S.DetailContent>
<S.DetailContent aria-label="선택지 내용">{text}</S.DetailContent>
)}
{isVoted && (
<>
<S.ProgressContainer>
<S.ProgressContainer aria-label={''}>
<ProgressBar percent={percent} isSelected={isSelected} />
</S.ProgressContainer>
<S.TextContainer>
<S.PeopleText>{peopleCount}명</S.PeopleText>
<S.PercentText>({percent.toFixed(1)}%)</S.PercentText>
<S.PeopleText aria-label="투표한 인원">{peopleCount}명</S.PeopleText>
<S.PercentText aria-label="전체 투표 중 차지 비율">
({percent.toFixed(1)}%)
</S.PercentText>
</S.TextContainer>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { styled } from 'styled-components';

import { theme } from '@styles/theme';

export const Container = styled.li<{ $isSelected: boolean }>`
export const Container = styled.button<{ $isSelected: boolean }>`
display: flex;
flex-direction: column;
align-items: stretch;

border: ${({ $isSelected }) =>
$isSelected ? '2px solid var(--primary-color)' : '1px solid rgba(0, 0, 0, 0.1)'};
Expand All @@ -13,6 +14,8 @@ export const Container = styled.li<{ $isSelected: boolean }>`

color: #5b5b5b;

text-align: left;

cursor: pointer;

@media (min-width: ${theme.breakpoint.md}) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ export default function WrittenVoteOptionList({
handleVoteClick,
}: WrittenVoteOptionListProps) {
return (
<S.VoteOptionListContainer>
{voteOptionList.map(voteOption => (
<S.VoteOptionListContainer aria-label="투표 선택지">
{voteOptionList.map((voteOption, index) => (
<WrittenVoteOption
ariaLabel={`${index + 1}번`}
key={voteOption.id}
{...voteOption}
isPreview={isPreview}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { styled } from 'styled-components';

import { theme } from '@styles/theme';

export const VoteOptionListContainer = styled.ul`
export const VoteOptionListContainer = styled.div`
display: flex;
flex-direction: column;
gap: 12px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default function OptionStatistics({
return (
<S.Container>
<WrittenVoteOption
ariaLabel=""
key={voteOption.id}
{...voteOption}
isPreview={false}
Expand Down