Skip to content

Commit

Permalink
[FE] feat: 꿀조합 전체 목록 페이지 구현(마크업) (#403)
Browse files Browse the repository at this point in the history
* feat: 꿀조합 목데이터 작성

* feat: RecipeItem 컴포넌트 추가

* feat: RecipeList 컴포넌트 추가

* feat: 날짜 포맷팅 유틸 함수 작성

* feat: 꿀조합 페이지 정렬 버튼 추가

* refactor: 스크롤버튼 스타일 수정

* feat: 꿀조합 페이지 제목 추가

* feat: 꿀조합 상세 링크 추가

* feat: 꿀조합 작성하기 버튼 추가

* refactor: 스크롤 버튼 스타일 수정

* refactor: alt 추가, 스타일 수정

* refactor: 꿀조합 페이지 텍스트 상수화

* style: css 컨벤션 수정

* feat: 꿀조합 목록 목 데이터에 상품 추가
  • Loading branch information
Leejin-Yang authored Aug 13, 2023
1 parent 78b01fd commit 34d9c90
Show file tree
Hide file tree
Showing 17 changed files with 393 additions and 6 deletions.
8 changes: 6 additions & 2 deletions frontend/src/components/Common/ScrollButton/ScrollButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ const ScrollButton = () => {
export default ScrollButton;

const ScrollButtonWrapper = styled(Button)`
position: absolute;
position: fixed;
bottom: 90px;
right: 32%;
right: 20px;
border-radius: 50%;
&:hover {
transform: scale(1.1);
transition: all 200ms ease-in-out;
}
@media screen and (min-width: 600px) {
left: calc(50% + 234px);
}
`;
1 change: 1 addition & 0 deletions frontend/src/components/Layout/AuthLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const AuthLayoutContainer = styled.div`
`;

const MainWrapper = styled.main`
position: relative;
height: 100%;
padding: 20px;
overflow-y: auto;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/Layout/DefaultLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const DefaultLayoutContainer = styled.div`
`;

const MainWrapper = styled.main`
position: relative;
height: calc(100% - 120px);
padding: 20px;
overflow-y: auto;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/Layout/DetailLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const DetailLayoutContainer = styled.div`
`;

const MainWrapper = styled.main`
position: relative;
height: calc(100% - 60px);
padding: 20px;
overflow-y: auto;
Expand Down
18 changes: 18 additions & 0 deletions frontend/src/components/Recipe/RecipeItem/RecipeItem.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Meta, StoryObj } from '@storybook/react';

import RecipeItem from './RecipeItem';

import mockRecipe from '@/mocks/data/recipes.json';

const meta: Meta<typeof RecipeItem> = {
title: 'recipe/RecipeItem',
component: RecipeItem,
args: {
recipe: mockRecipe.recipes[0],
},
};

export default meta;
type Story = StoryObj<typeof RecipeItem>;

export const Default: Story = {};
97 changes: 97 additions & 0 deletions frontend/src/components/Recipe/RecipeItem/RecipeItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Heading, Text, useTheme } from '@fun-eat/design-system';
import styled from 'styled-components';

import { SvgIcon } from '@/components/Common';
import type { Recipe } from '@/types/recipe';
import { getFormattedDate } from '@/utils/date';

interface RecipeItemProps {
recipe: Recipe;
}

const RecipeItem = ({ recipe }: RecipeItemProps) => {
const { image, title, author, createdAt, favoriteCount, products } = recipe;
const theme = useTheme();

return (
<RecipeItemContainer>
<ImageWrapper>
<RecipeImage src={image} alt={`조리된 ${title}`} />
<ProfileImage src={author.profileImage} alt={`${author.nickname}의 프로필`} />
</ImageWrapper>
<RecipeInfoWrapper>
<Text color={theme.textColors.sub}>
{author.nickname} 님 | {getFormattedDate(createdAt)}
</Text>
<Heading as="h3" size="xl" weight="bold">
{title}
</Heading>
<Text>
{products.map(({ id, name }) => (
<>
<Text as="span" key={id} color={theme.textColors.info}>
#{name}
</Text>{' '}
</>
))}
</Text>
<FavoriteWrapper>
<SvgIcon variant="favoriteFilled" width={16} height={16} />
<Text as="span" weight="bold">
{favoriteCount}
</Text>
</FavoriteWrapper>
</RecipeInfoWrapper>
</RecipeItemContainer>
);
};

export default RecipeItem;

const RecipeItemContainer = styled.div`
height: 280px;
`;

const ImageWrapper = styled.div`
position: relative;
width: 100%;
height: 160px;
`;

const RecipeImage = styled.img`
width: 100%;
height: 100%;
border-radius: 8px;
object-fit: cover;
`;

const ProfileImage = styled.img`
position: absolute;
right: 16px;
bottom: -20px;
width: 60px;
height: 60px;
border-radius: 50%;
background-color: ${({ theme }) => theme.backgroundColors.default};
border: 2px solid ${({ theme }) => theme.colors.primary};
`;

const RecipeInfoWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
height: 100px;
margin-top: 20px;
`;

const FavoriteWrapper = styled.div`
display: flex;
align-items: center;
gap: 4px;
position: absolute;
top: 50%;
right: 0;
bottom: 50%;
transform: translateY(-50%);
`;
13 changes: 13 additions & 0 deletions frontend/src/components/Recipe/RecipeList/RecipeList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Meta, StoryObj } from '@storybook/react';

import RecipeList from './RecipeList';

const meta: Meta<typeof RecipeList> = {
title: 'recipe/RecipeList',
component: RecipeList,
};

export default meta;
type Story = StoryObj<typeof RecipeList>;

export const Default: Story = {};
32 changes: 32 additions & 0 deletions frontend/src/components/Recipe/RecipeList/RecipeList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Link } from '@fun-eat/design-system';
import { Link as RouterLink } from 'react-router-dom';
import styled from 'styled-components';

import RecipeItem from '../RecipeItem/RecipeItem';

import recipeResponse from '@/mocks/data/recipes.json';

const RecipeList = () => {
// TODO: 임시 데이터, API 연동 후 수정
const { recipes } = recipeResponse;

return (
<RecipeListContainer>
{recipes.map((recipe) => (
<li key={recipe.id}>
<Link as={RouterLink} to={`${recipe.id}`}>
<RecipeItem recipe={recipe} />
</Link>
</li>
))}
</RecipeListContainer>
);
};

export default RecipeList;

const RecipeListContainer = styled.ul`
& > li + li {
margin-top: 40px;
}
`;
2 changes: 2 additions & 0 deletions frontend/src/components/Recipe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as RecipeItem } from './RecipeItem/RecipeItem';
export { default as RecipeList } from './RecipeList/RecipeList';
2 changes: 1 addition & 1 deletion frontend/src/components/Review/ReviewItem/ReviewItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { SvgIcon, TagList } from '@/components/Common';
import { useTimeout } from '@/hooks/common';
import { useReviewFavoriteMutation } from '@/hooks/queries/review';
import type { Review } from '@/types/review';
import { getRelativeDate } from '@/utils/relativeDate';
import { getRelativeDate } from '@/utils/date';

interface ReviewItemProps {
productId: number;
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ export const REVIEW_SORT_OPTIONS = [
{ label: '추천순', value: 'favoriteCount,desc' },
] as const;

export const RECIPE_SORT_OPTIONS = [
{ label: '최신 작성순', value: 'createdAt,desc' },
{ label: '추천순', value: 'favoriteCount,desc' },
] as const;

export const TAG_TITLE = {
TASTE: '맛',
PRICE: '가격/양',
Expand Down
84 changes: 84 additions & 0 deletions frontend/src/mocks/data/recipes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"page": {
"totalDataCount": 99,
"totalPages": 10,
"isLastPage": false,
"isFirstPage": true,
"requestPage": 1,
"requestSize": 10
},
"recipes": [
{
"id": 1,
"image": "https://github.com/woowacourse-teams/2023-fun-eat/assets/78616893/1f0fd418-131c-4cf8-b540-112d762b7c34",
"title": "치즈함박카레라이스",
"author": {
"nickname": "냐미",
"profileImage": "https://github.com/woowacourse-teams/2023-fun-eat/assets/78616893/991f7b69-53bf-4d03-96e1-988c34d010ed"
},
"createdAt": "2023-08-09T10:10:10",
"favoriteCount": 153,
"products": [
{ "id": 11, "name": "불닭볶음면", "price": 1500 },
{ "id": 12, "name": "치즈", "price": 1500 },
{ "id": 13, "name": "콘치즈", "price": 1500 }
]
},
{
"id": 2,
"image": "https://github.com/woowacourse-teams/2023-fun-eat/assets/78616893/1f0fd418-131c-4cf8-b540-112d762b7c34",
"title": "초특급불닭콘치즈",
"author": {
"nickname": "뇨미",
"profileImage": "https://github.com/woowacourse-teams/2023-fun-eat/assets/78616893/84a20dae-4770-4497-ae25-2dd552261aab"
},
"createdAt": "2023-08-10T10:10:10",
"favoriteCount": 154,
"products": [
{ "id": 11, "name": "불닭볶음면", "price": 1500 },
{ "id": 12, "name": "치즈", "price": 1500 },
{ "id": 13, "name": "콘치즈", "price": 1500 },
{ "id": 14, "name": "치즈", "price": 1500 },
{ "id": 15, "name": "콘치즈", "price": 1500 }
]
},
{
"id": 3,
"image": "https://t3.ftcdn.net/jpg/06/06/91/70/240_F_606917032_4ujrrMV8nspZDX8nTgGrTpJ69N9JNxOL.jpg",
"title": "치즈함박카레라이스2",
"author": {
"nickname": "냐미",
"profileImage": "https://github.com/woowacourse-teams/2023-fun-eat/assets/78616893/991f7b69-53bf-4d03-96e1-988c34d010ed"
},
"createdAt": "2023-08-01T10:10:10",
"favoriteCount": 1531,
"products": [
{ "id": 11, "name": "불닭볶음면", "price": 1500 },
{ "id": 12, "name": "치즈", "price": 1500 },
{ "id": 13, "name": "콘치즈", "price": 1500 },
{ "id": 14, "name": "치즈", "price": 1500 },
{ "id": 15, "name": "콘치즈", "price": 1500 },
{ "id": 16, "name": "콘치즈", "price": 1500 }
]
},
{
"id": 4,
"image": "https://cdn.pixabay.com/photo/2016/03/23/15/00/ice-cream-1274894_1280.jpg",
"title": "초특급불닭콘치즈2",
"author": {
"nickname": "뇨미",
"profileImage": "https://github.com/woowacourse-teams/2023-fun-eat/assets/78616893/84a20dae-4770-4497-ae25-2dd552261aab"
},
"createdAt": "2023-08-06T10:10:10",
"favoriteCount": 120,
"products": [
{ "id": 11, "name": "불닭볶음면", "price": 1500 },
{ "id": 12, "name": "치즈", "price": 1500 },
{ "id": 13, "name": "콘치즈", "price": 1500 },
{ "id": 14, "name": "치즈", "price": 1500 },
{ "id": 15, "name": "콘치즈", "price": 1500 },
{ "id": 16, "name": "콘치즈", "price": 1500 }
]
}
]
}
4 changes: 2 additions & 2 deletions frontend/src/pages/ProductDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ const ProductDetailPage = () => {
type="button"
customWidth="100%"
customHeight="60px"
color={!member ? 'gray3' : 'primary'}
textColor={!member ? 'white' : 'default'}
color={member ? 'primary' : 'gray3'}
textColor={member ? 'default' : 'white'}
size="xl"
weight="bold"
onClick={handleOpenRegisterReviewSheet}
Expand Down
Loading

0 comments on commit 34d9c90

Please sign in to comment.