Skip to content

Commit

Permalink
design: 톡앤픽 플레이스 Page UI 구현 (#155)
Browse files Browse the repository at this point in the history
* feat: TalkPickItem 컴포넌트 UI 구현 및 스토리북 추가

* feat: BestTalkPick 컴포넌트 UI 구현 및 스토리북 추가

* feat: TalkPickList 컴포넌트 UI 구현 및 스토리북 추가

* feat: TalkPickListSection 컴포넌트 UI 구현 및 스토리북 추가

* design: TalkPickPlacePage UI 구현

* refactor: header, footer 스타일 수정 및 layout 병합

* refactor: TalkPickItem 스토리북 오타 수정
  • Loading branch information
areumH authored Aug 12, 2024
1 parent e82341a commit 5856af1
Show file tree
Hide file tree
Showing 22 changed files with 812 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import SearchResultPage from './pages/SearchResultPage/SearchResultPage';
import SignUpPage from './pages/SignUpPage/SignUpPage';
import { useNewSelector } from './store';
import { selectAccessToken } from './store/auth';
import TalkPickPlacePage from './pages/TalkPickPlacePage/TalkPickPlacePage';

const App: React.FC = () => {
const accessToken = useNewSelector(selectAccessToken);
Expand All @@ -38,6 +39,7 @@ const App: React.FC = () => {
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<LandingPage />} />
<Route path="/talkpickplace" element={<TalkPickPlacePage />} />
{/* <Route path="posts" element={<PostList />} />
<Route path="posts/:id" element={<PostPage />} />
<Route path="searchResult" element={<SearchResultPage />} />
Expand Down
1 change: 1 addition & 0 deletions src/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export { default as Popular } from './svg/popular.svg';
export { default as Couple } from './svg/couple.svg';
export { default as Taste } from './svg/taste.svg';
export { default as Worldcup } from './svg/worldcup.svg';
export { default as TalkPickBubble } from './svg/talk-pick-bubble.svg';

// TODO: 이전 SVG
export { default as Email } from './svg/email.svg';
Expand Down
9 changes: 9 additions & 0 deletions src/assets/svg/talk-pick-bubble.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
104 changes: 104 additions & 0 deletions src/components/atoms/TalkPickItem/TalkPickItem.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { css } from '@emotion/react';
import typo from '@/styles/typo';
import color from '@/styles/color';
import type { TalkPickListItemProps } from './TalkPickItem';

export const commonNumberStyle = css(typo.Number.Medium, {
color: color.GY[1],
});

export const bestNumberStyle = css(typo.Number.Medium, {
color: color.MAIN,
});

export const commonStyle = css(typo.Comment.SemiBold, {
color: color.GY[1],
});

export const headerStyle = css(typo.Main.Medium, {
color: color.BK,
});

export const borderBottomStyling = css({
borderBottom: '1px solid #F4F4F4',
});

export const centerStyling = css({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
});

export const talkPickListItemStyling = css({
display: 'flex',
alignItems: 'center',
width: '1174px',
height: '60px',
});

export const talkPickListId = css([
centerStyling,
{
width: '112px',
color: color.GY[1],
},
]);

export const getTalkPickListIdStyling = (
type: Required<TalkPickListItemProps>['type'],
) => {
return type === 'best' ? bestNumberStyle : commonNumberStyle;
};

export const talkPickListTitle = css({
width: '570px',
padding: '0 10px',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
color: color.BK,
});

export const talkPickTitleText = css({
cursor: 'pointer',
});

export const getTalkPickListTitleStyling = (
type: Required<TalkPickListItemProps>['type'],
) => {
const style = {
header: css(typo.Main.Medium, centerStyling),
default: css(typo.Main.Medium),
best: css(typo.Main.SemiBold, {
fontWeight: 'bold',
}),
};

return style[type];
};

export const getTalkPickListWriterStyling = (
type: Required<TalkPickListItemProps>['type'],
) => {
return type === 'header' ? headerStyle : commonStyle;
};

export const talkPickListWideDetail = css([
centerStyling,
{
width: '148px',
},
]);

export const talkPickListDetail = css([
centerStyling,
{
width: '85px',
},
]);

export const getTalkPickListDetailStyling = (
type: Required<TalkPickListItemProps>['type'],
) => {
return type === 'header' ? headerStyle : commonNumberStyle;
};
77 changes: 77 additions & 0 deletions src/components/atoms/TalkPickItem/TalkPickItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import { TalkPickListItem } from '@/types/talk-pick';
import { formatDate, formatNumber } from '@/utils/formatData';
import * as S from './TalkPickItem.style';

export interface TalkPickListItemProps {
type?: 'header' | 'default' | 'best';
rank?: number;
talkPickItem?: TalkPickListItem;
}

const headerTalkPick: TalkPickListItem = {
id: 0,
title: '제목',
writer: '작성자',
createdAt: '작성일시',
views: '조회수',
bookmarks: '저장수',
};

const TalkPickItem = ({
type = 'default',
rank,
talkPickItem = headerTalkPick,
}: TalkPickListItemProps) => {
const getTalkPickId = (): number | undefined => {
switch (type) {
case 'default':
return talkPickItem.id;
case 'best':
return rank;
case 'header':
default:
return undefined;
}
};

const getFormatNumber = (item: number | string): string => {
return typeof item === 'number' ? formatNumber(item) : item;
};

return (
<div
css={[
S.talkPickListItemStyling,
type !== 'header' && S.borderBottomStyling,
]}
>
<div css={[S.talkPickListId, S.getTalkPickListIdStyling(type)]}>
{getTalkPickId()}
</div>
<div css={[S.talkPickListTitle, S.getTalkPickListTitleStyling(type)]}>
<span css={type !== 'header' && S.talkPickTitleText}>
{talkPickItem.title}
</span>
</div>
<div
css={[S.talkPickListWideDetail, S.getTalkPickListWriterStyling(type)]}
>
{talkPickItem.writer}
</div>
<div
css={[S.talkPickListWideDetail, S.getTalkPickListDetailStyling(type)]}
>
{formatDate(talkPickItem.createdAt)}
</div>
<div css={[S.talkPickListDetail, S.getTalkPickListDetailStyling(type)]}>
{getFormatNumber(talkPickItem.views)}
</div>
<div css={[S.talkPickListDetail, S.getTalkPickListDetailStyling(type)]}>
{getFormatNumber(talkPickItem.bookmarks)}
</div>
</div>
);
};

export default TalkPickItem;
18 changes: 18 additions & 0 deletions src/components/molecules/BestTalkPick/BestTalkPick.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { css } from '@emotion/react';
import typo from '@/styles/typo';
import color from '@/styles/color';

export const bestTalkPickContainer = css({
display: 'flex',
flexDirection: 'column',
paddingTop: '30px',
paddingBottom: '40px',
borderRadius: '20px',
border: `1px solid ${color.GY[2]}`,
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
});

export const bestTalkPickText = css(typo.Title, {
padding: '0 40px',
color: color.MAIN,
});
25 changes: 25 additions & 0 deletions src/components/molecules/BestTalkPick/BestTalkPick.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { TalkPickListItem } from '@/types/talk-pick';
import TalkPickItem from '@/components/atoms/TalkPickItem/TalkPickItem';
import * as S from './BestTalkPick.style';

export interface BestTalkPickProps {
bestTalkPick: TalkPickListItem[];
}

const BestTalkPick = ({ bestTalkPick }: BestTalkPickProps) => (
<div css={S.bestTalkPickContainer}>
<div css={S.bestTalkPickText}>BEST 3</div>
<TalkPickItem type="header" />
{bestTalkPick.map((talkPick, idx) => (
<TalkPickItem
key={talkPick.id}
type="best"
rank={idx + 1}
talkPickItem={talkPick}
/>
))}
</div>
);

export default BestTalkPick;
14 changes: 14 additions & 0 deletions src/components/molecules/TalkPickList/TalkPickList.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { css } from '@emotion/react';
import color from '@/styles/color';

export const talkPickListContainer = css({
display: 'flex',
flexDirection: 'column',
padding: '12px 0',
borderTop: `1px solid ${color.GY[2]}`,
});

export const talkPickListWrapper = css({
display: 'flex',
flexDirection: 'column',
});
25 changes: 25 additions & 0 deletions src/components/molecules/TalkPickList/TalkPickList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { TalkPickListItem } from '@/types/talk-pick';
import TalkPickItem from '@/components/atoms/TalkPickItem/TalkPickItem';
import * as S from './TalkPickList.style';

export interface TalkPickListProps {
talkPickList: TalkPickListItem[];
}

const TalkPickList = ({ talkPickList }: TalkPickListProps) => (
<div css={S.talkPickListContainer}>
<div css={S.talkPickListWrapper}>
<TalkPickItem type="header" />
{talkPickList.map((talkPick) => (
<TalkPickItem
key={talkPick.id}
type="default"
talkPickItem={talkPick}
/>
))}
</div>
</div>
);

export default TalkPickList;
2 changes: 1 addition & 1 deletion src/components/organisms/Footer/Footer.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const footerContainer = css`
display: flex;
flex-direction: column;
background-color: ${color.BLUE_LIGHT};
width: 1920px;
width: 100%;
height: 427px;
padding-left: 200px;
`;
Expand Down
3 changes: 2 additions & 1 deletion src/components/organisms/Header/Header.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export const containerStyle = css({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#ffffff',
backgroundColor: color.WT,
boxShadow: '0px 4px 11px rgba(0, 0, 0, 0.1)',
});

export const logoStyle = css({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { css } from '@emotion/react';

export const talkPickListContainer = css({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
});

export const talkPickBtnWrapper = css({
display: 'flex',
justifyContent: 'space-between',
width: '100%',
alignItems: 'flex-end',
padding: '0 5px',
});

export const talkPickListWrapper = css({
paddingTop: '10px',
paddingBottom: '60px',
});

export const talkPickWriteBtnWrapper = css({
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
gap: '5px',
});

export const talkPickWriteBtn = css({
width: '108px',
marginRight: '5px',
});
Loading

0 comments on commit 5856af1

Please sign in to comment.