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

[FE] 페어 목록 리스트 구현 #117

Merged
merged 5 commits into from
Jul 25, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Meta, StoryObj } from '@storybook/react';

import DeleteButton from './DeleteButton';

const meta = {
title: 'component/PairRoom/PairListCard/DeleteButton',
component: DeleteButton,
} satisfies Meta<typeof DeleteButton>;

export default meta;

type Story = StoryObj<typeof DeleteButton>;

export const Default: Story = {
args: {
isOpen: true,
onRoomDelete: () => alert('Room deleted'),
},
};

export const Closed: Story = {
args: {
isOpen: false,
onRoomDelete: () => alert('Room deleted'),
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import styled from 'styled-components';

export const Layout = styled.button`
position: absolute;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 4.8rem;
gap: 0.8rem;
background-color: ${({ theme }) => theme.color.danger[200]};
border-radius: 0 0 2rem 2rem;
color: ${({ theme }) => theme.color.danger[600]};
font-size: ${({ theme }) => theme.fontSize.md};
cursor: pointer;
margin-top: auto;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FaTrashAlt } from 'react-icons/fa';

import * as S from './DeleteButton.styles';

interface DeleteButtonProps {
isOpen: boolean;
onRoomDelete: () => void;
}

const DeleteButton = ({ isOpen, onRoomDelete }: DeleteButtonProps) => (
<S.Layout onClick={onRoomDelete}>
<FaTrashAlt size="1.5rem" />
{isOpen && <span>방 삭제하기</span>}
</S.Layout>
);

export default DeleteButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Meta, StoryObj } from '@storybook/react';

import Header from './Header';

const meta = {
title: 'component/PairRoom/PairListCard/Header',
component: Header,
} satisfies Meta<typeof Header>;

export default meta;

type Story = StoryObj<typeof Header>;

export const Default: Story = {
args: {
isOpen: true,
},
};

export const Closed: Story = {
args: {
isOpen: false,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IoIosArrowBack } from 'react-icons/io';
import styled from 'styled-components';

import { PairRoomCard } from '@/components/PairRoom/PairRoomCard';

export const Layout = styled(PairRoomCard.Header)`
p {
height: 4.8rem;
white-space: nowrap;
}
`;

export const ArrowIcon = styled(IoIosArrowBack)<{ $isOpen: boolean }>`
transform: rotate(${({ $isOpen }) => ($isOpen ? 0 : 180)}deg);
transition: transform 0.2s ease-in-out;
`;
17 changes: 17 additions & 0 deletions frontend/src/components/PairRoom/PairListCard/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { IoPeople } from 'react-icons/io5';

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

import * as S from './Header.styles';

interface HeaderProps {
isOpen: boolean;
}

const Header = ({ isOpen }: HeaderProps) => (
<S.Layout icon={isOpen ? <IoPeople color={theme.color.primary[500]} /> : <></>} title={isOpen ? '페어' : ''}>
<S.ArrowIcon $isOpen={isOpen} />
</S.Layout>
);

export default Header;
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,10 @@ export default meta;
type Story = StoryObj<typeof PairListCard>;

export const Default: Story = {
args: {},
args: {
roomCode: 'IUUIASDFJK',
driver: '퍼렁',
navigator: '포롱',
onRoomDelete: () => alert('방이 삭제되었습니다.'),
},
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import styled from 'styled-components';

export const Layout = styled.div`
export const Layout = styled.div<{ $isOpen: boolean }>`
position: relative;
display: flex;
width: 18vw;
flex-direction: column;
width: ${(props) => (props.$isOpen ? '16vw' : '6rem')};
min-width: ${(props) => (props.$isOpen ? '20rem' : '6rem')};
min-height: 40rem;
align-items: center;
justify-content: center;
transition: all 0.3s;
white-space: nowrap;
`;

export const Sidebar = styled.div`
overflow: hidden;
`;
34 changes: 27 additions & 7 deletions frontend/src/components/PairRoom/PairListCard/PairListCard.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
import { IoPeople } from 'react-icons/io5';
import { useState } from 'react';

import DeleteButton from '@/components/PairRoom/PairListCard/DeleteButton/DeleteButton';
import Header from '@/components/PairRoom/PairListCard/Header/Header';
import PairListSection from '@/components/PairRoom/PairListCard/PairListSection/PairListSection';
import RoomCodeSection from '@/components/PairRoom/PairListCard/RoomCodeSection/RoomCodeSection';
import { PairRoomCard } from '@/components/PairRoom/PairRoomCard';

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

import * as S from './PairListCard.styles';

// TODO: 페어 목록 기능 추가
const PairListCard = () => {
interface PairListCardProps {
driver: string;
navigator: string;
roomCode: string;
onRoomDelete: () => void;
}

const PairListCard = ({ driver, navigator, roomCode, onRoomDelete }: PairListCardProps) => {
const [isOpen, setIsOpen] = useState(false);

const onCopy = () => {
window.navigator.clipboard.writeText(roomCode);
alert('방 코드가 복사되었습니다.');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

window 를 생략할수도 있을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생락하면 계속 오류가 발생하더라구요 ㅠㅠ
일단은 이대로 유지하겠습니다 😢

};

return (
<S.Layout>
<S.Layout $isOpen={isOpen} onMouseOver={() => setIsOpen(true)} onMouseLeave={() => setIsOpen(false)}>
<PairRoomCard>
<PairRoomCard.Header icon={<IoPeople color={theme.color.primary[500]} />} title="페어" />
<Header isOpen={isOpen} />
<S.Sidebar>
<RoomCodeSection isOpen={isOpen} roomCode={roomCode} onCopy={onCopy} />
<PairListSection isOpen={isOpen} driver={driver} navigator={navigator} />
<DeleteButton isOpen={isOpen} onRoomDelete={onRoomDelete} />
</S.Sidebar>
</PairRoomCard>
</S.Layout>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { Meta, StoryObj } from '@storybook/react';

import PairListSection from './PairListSection';

const meta = {
title: 'component/PairRoom/PairListCard/PairListSection',
component: PairListSection,
} satisfies Meta<typeof PairListSection>;

export default meta;

type Story = StoryObj<typeof PairListSection>;

export const Default: Story = {
args: {
isOpen: true,
driver: '퍼렁',
navigator: '포롱',
},
};

export const Closed: Story = {
args: {
isOpen: false,
driver: '퍼렁',
navigator: '포롱',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import styled from 'styled-components';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희 피그마 시안에는 border 가 있는데 제공해 주신 영상은 피그마 시안과 다른 것처럼 보여요. 혹시 다르게 디자인이 된 이유가 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isOpen때 border가 조금 짧아서 보류하고 있었어요. 반영했습니다 😊


type Role = 'driver' | 'navigator';

export const Layout = styled.div`
padding: 0 1.6rem;
column-gap: 1.6rem;
justify-content: center;
align-items: center;
`;

export const PairItem = styled.div`
display: flex;
align-items: center;
justify-content: start;
height: 7rem;
gap: 1.6rem;
border-bottom: 1px solid ${({ theme }) => theme.color.black[40]};
`;

export const PairRole = styled.span<{ $role: Role }>`
padding: 0.4rem 0.8rem;
border-radius: 1.2rem;
width: 6rem;
text-align: center;
background-color: ${({ theme, $role }) =>
$role === 'driver' ? theme.color.primary[500] : theme.color.secondary[500]};
color: white;
`;

export const PairName = styled.span`
font-size: ${({ theme }) => theme.fontSize.base};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as S from './PairListSection.styles';

interface PairListSectionProps {
isOpen: boolean;
driver: string;
navigator: string;
}

const PairListSection = ({ isOpen, driver, navigator }: PairListSectionProps) => (
<S.Layout>
<S.PairItem>
{isOpen && <S.PairRole $role="driver">드라이버</S.PairRole>}
<S.PairName>{driver}</S.PairName>
</S.PairItem>
<S.PairItem>
{isOpen && <S.PairRole $role="navigator">네비게이터</S.PairRole>}
<S.PairName>{navigator}</S.PairName>
</S.PairItem>
</S.Layout>
);

export default PairListSection;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { Meta, StoryObj } from '@storybook/react';

import RoomCodeSection from './RoomCodeSection';

const meta = {
title: 'component/PairRoom/PairListCard/RoomCodeSection',
component: RoomCodeSection,
} satisfies Meta<typeof RoomCodeSection>;

export default meta;

type Story = StoryObj<typeof RoomCodeSection>;

export const Default: Story = {
args: {
isOpen: true,
roomCode: 'IUUIASDFJK',
onCopy: () => alert('Room code copied'),
},
};

export const Closed: Story = {
args: {
isOpen: false,
roomCode: 'IUUIASDFJK',
onCopy: () => alert('Room code copied'),
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import styled from 'styled-components';

export const Layout = styled.div<{ $isOpen: boolean }>`
display: flex;
align-items: center;
justify-content: ${({ $isOpen }) => ($isOpen ? 'space-between' : 'center')};
width: 100%;
height: 7rem;
background-color: ${({ $isOpen, theme }) => ($isOpen ? theme.color.black[30] : 'white')};
padding: 2rem;
cursor: pointer;
transition: background-color 0.3s ease-out;
`;

export const RoomCodeWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
gap: 1.2rem;
`;

export const RoomCodeTitle = styled.span`
font-size: ${({ theme }) => theme.fontSize.base};
font-weight: ${({ theme }) => theme.fontWeight.bold};
color: ${({ theme }) => theme.color.black[70]};
height: 2rem;
`;

export const RoomCode = styled.span`
font-size: ${({ theme }) => theme.fontSize.md};
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { FaRegPaste } from 'react-icons/fa6';

import * as S from './RoomCodeSection.styles';

interface RoomCodeSectionProps {
isOpen: boolean;
roomCode: string;
onCopy: () => void;
}

const RoomCodeSection = ({ isOpen, roomCode, onCopy }: RoomCodeSectionProps) => (
<S.Layout $isOpen={isOpen} onClick={onCopy}>
{isOpen && (
<S.RoomCodeWrapper>
<S.RoomCodeTitle>방 코드</S.RoomCodeTitle>
<S.RoomCode>{roomCode}</S.RoomCode>
</S.RoomCodeWrapper>
)}
<FaRegPaste size="1.5rem" />
</S.Layout>
);

export default RoomCodeSection;
2 changes: 1 addition & 1 deletion frontend/src/pages/PairRoom/PairRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as S from './PairRoom.styles';
const PairRoom = () => {
return (
<S.Layout>
<PairListCard />
<PairListCard driver="퍼렁" navigator="포롱" roomCode="IUUIASDFJK" onRoomDelete={() => {}} />
<S.Container>
<PairRoleCard />
<TimerCard />
Expand Down
Loading