Skip to content

Commit

Permalink
feat: 꿀조합 페이지 구현 (#66)
Browse files Browse the repository at this point in the history
* refactor: recipeItem 디자인 수정

* feat: disk 아이콘 추가

* refactor: type 및 속성 원상복구

* feat: recipeProductButton 구현

* refactor: recipeProductButton 컴포넌트 추가

* refactor: 스타일 재구성 및 바닐라 마이그레이션 진행

* refactor: 스크롤, 레시피 작성 버튼 스타일 변경

* refactor: recipe 컴포넌트 스타일 수정

* refactor: product type 추가

* refactor: recipe page layout 변경

* refactor: sort button 디자인 수정 및 바닐라 마이그레이션

* feat: arrowUpDown 추가

* refactor: favoriteCount type 추가

* refactor: recipe page 디자인 변경

* feat: ProductOverviewList 구현

* refactor: type 및 데이터 값 변경

* refactor: 빠진 속성, 띄어쓰기 추가

* refactor: 사용한 상품 바텀시트 구현

* refactor: productOverviewList로 대체

* refactor: 링크 이동 기능 내부 버튼에는 적용 안되도록 수정

* chore: lint 적용

* refactor: null ??로 처리

* chore: 잘못 작성한 코드 삭제

* refactor: recipe product type 정의

* refactor: 스켈레톤 조건 추가

* refactor: 간격 디자인 수정

* refactor: member가 아닐 때는 button -> div로 변경

* refactor: favorite count 삭제

* refactor: 상품 상세 변경

* refactor: 스크롤 높이 적용
  • Loading branch information
hae-on authored Apr 8, 2024
1 parent 161aaf6 commit 6c8ae2b
Show file tree
Hide file tree
Showing 42 changed files with 643 additions and 387 deletions.
20 changes: 20 additions & 0 deletions .storybook/preview-body.html
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,13 @@
/>
</symbol>
</symbol>
<symbol id="arrowUpDown" viewBox="0 0 15 16">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.229 13.549V2.45l2.925 2.925M5.549 2.451V13.55l-2.926-2.926"
/>
</symbol>
<symbol id="heartEmpty" viewBox="0 0 24 23">
<path
fill="#fff"
Expand Down Expand Up @@ -314,6 +321,19 @@
<path d="M11.3705 0.81424L1.15625 11.0285" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />
<path d="M1.15625 0.81424L11.3705 11.0285" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" />
</symbol>
<symbol id="disk" viewBox="0 0 12 13">
<g stroke-linecap="round" stroke-linejoin="round" clip-path="url(#a)">
<path
d="M10.713.847H1.285a.857.857 0 0 0-.857.857v9.429c0 .473.383.857.857.857h9.428a.857.857 0 0 0 .858-.857V1.704a.857.857 0 0 0-.858-.857z"
/>
<path d="M7.714.847v4.286a.429.429 0 0 1-.429.428H4.714a.429.429 0 0 1-.429-.428V.847m3 9h2.143" />
</g>
<defs>
<clipPath id="a">
<path d="M0 0h12v12H0z" transform="translate(0 .418)" />
</clipPath>
</defs>
</symbol>
</svg>
</div>
<div id="dialog-container"></div>
Expand Down
5 changes: 0 additions & 5 deletions src/components/Common/ScrollButton/scrollButton.css.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { style } from '@vanilla-extract/css';

export const container = style({
position: 'sticky',
// 임의로 작성한 값. 추후 수정 예정
bottom: 100,
right: 20,
width: 40,
height: 40,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
background: '#F9F9F9',
borderRadius: '50%',
float: 'right',
});
20 changes: 4 additions & 16 deletions src/components/Common/SortButton/SortButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Button, useTheme } from '@fun-eat/design-system';
import styled from 'styled-components';

import { container } from './sortButton.css';
import SvgIcon from '../Svg/SvgIcon';

import type { SortOption } from '@/types/common';
Expand All @@ -11,22 +9,12 @@ interface SortButtonProps {
}

const SortButton = ({ option, onClick }: SortButtonProps) => {
const theme = useTheme();

return (
<SortButtonContainer type="button" weight="bold" textColor="info" variant="transparent" onClick={onClick}>
<SvgIcon variant="sort" fill={theme.textColors.info} width={18} height={18} />
<button type="button" className={container} onClick={onClick}>
<SvgIcon variant="arrowUpDown" stroke="#3D3D3D" fill="none" width={14} height={14} />
{option.label}
</SortButtonContainer>
</button>
);
};

export default SortButton;

const SortButtonContainer = styled(Button)`
display: flex;
justify-content: flex-end;
align-items: center;
padding: 0;
column-gap: 4px;
`;
10 changes: 10 additions & 0 deletions src/components/Common/SortButton/sortButton.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { style } from '@vanilla-extract/css';

export const container = style({
display: 'flex',
alignItems: 'center',
gap: 2,
color: '#3D3D3D',
fontSize: 14,
fontWeight: 600,
});
2 changes: 2 additions & 0 deletions src/components/Common/Svg/SvgIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ export const SVG_ICON_VARIANTS = [
'arrowUp',
'arrowLeft',
'arrowRight',
'arrowUpDown',
'heartEmpty',
'heartFilled',
'close2',
'disk',
] as const;
export type SvgIconVariant = (typeof SVG_ICON_VARIANTS)[number];

Expand Down
18 changes: 18 additions & 0 deletions src/components/Common/Svg/SvgSprite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ const SvgSprite = () => {
d="M14.475 12l-7.35-7.35q-.375-.375-.363-.888t.388-.887q.375-.375.888-.375t.887.375l7.675 7.7q.3.3.45.675t.15.75q0 .375-.15.75t-.45.675l-7.7 7.7q-.375.375-.875.363T7.15 21.1q-.375-.375-.375-.888t.375-.887z"
/>
</symbol>
<symbol id="arrowUpDown" viewBox="0 0 15 16">
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9.229 13.549V2.45l2.925 2.925M5.549 2.451V13.55l-2.926-2.926"
/>
</symbol>
<symbol id="heartEmpty" viewBox="0 0 24 23">
<path
fill="#fff"
Expand Down Expand Up @@ -274,6 +281,17 @@ const SvgSprite = () => {
<path d="M11.3705 0.81424L1.15625 11.0285" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
<path d="M1.15625 0.81424L11.3705 11.0285" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
</symbol>
<symbol id="disk" viewBox="0 0 12 13">
<g strokeLinecap="round" strokeLinejoin="round" clipPath="url(#a)">
<path d="M10.713.847H1.285a.857.857 0 0 0-.857.857v9.429c0 .473.383.857.857.857h9.428a.857.857 0 0 0 .858-.857V1.704a.857.857 0 0 0-.858-.857z" />
<path d="M7.714.847v4.286a.429.429 0 0 1-.429.428H4.714a.429.429 0 0 1-.429-.428V.847m3 9h2.143" />
</g>
<defs>
<clipPath id="a">
<path d="M0 0h12v12H0z" transform="translate(0 .418)" />
</clipPath>
</defs>
</symbol>
</svg>
);
};
Expand Down
3 changes: 1 addition & 2 deletions src/components/Common/WriteButton/WriteButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react';

import { button, closeButton, container, bubble } from './writeButton.css';
import { button, closeButton, bubble, container } from './writeButton.css';
import SvgIcon from '../Svg/SvgIcon';

import { useMemberQuery } from '@/hooks/queries/members';
Expand All @@ -13,7 +13,6 @@ const WriteButton = () => {

return (
<>
{/* 클릭 시 이동 (dialog 사용할 지, 페이지 이동할 지 미정) */}
<div className={container}>
{isShowBubble && (
<div className={bubble}>
Expand Down
16 changes: 5 additions & 11 deletions src/components/Common/WriteButton/writeButton.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,11 @@ const flexCenter = style({
justifyContent: 'center',
});

export const container = style([
flexCenter,
{
position: 'sticky',
// 임의로 작성한 값. 추후 수정 예정
bottom: 80,
right: 20,
gap: 6,
float: 'right',
},
]);
export const container = style({
display: 'flex',
alignItems: 'center',
gap: 6,
});

export const button = style([
flexCenter,
Expand Down
1 change: 1 addition & 0 deletions src/components/Common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ export { default as SectionHeader } from './SectionHeader/SectionHeader';
export { default as SelectOptionList } from './SelectOptionList/SelectOptionList';
export { default as PageHeader } from './PageHeader/PageHeader';
export { default as Badge } from './Badge/Badge';
export { default as WriteButton } from './WriteButton/WriteButton';
export { default as Text } from './Text/Text';
15 changes: 2 additions & 13 deletions src/components/Product/ProductDetailItem/ProductDetailItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,21 @@ import { Text, useTheme } from '@fun-eat/design-system';
import styled from 'styled-components';

import PreviewImage from '@/assets/characters.svg';
import PBPreviewImage from '@/assets/samgakgimbab.svg';
import { SvgIcon, TagList } from '@/components/Common';
import { CATEGORY_TYPE } from '@/constants';
import type { ProductDetail } from '@/types/product';

interface ProductDetailItemProps {
category: string;
productDetail: ProductDetail;
}

const ProductDetailItem = ({ category, productDetail }: ProductDetailItemProps) => {
const ProductDetailItem = ({ productDetail }: ProductDetailItemProps) => {
const { name, price, image, content, averageRating, tags } = productDetail;

const theme = useTheme();

return (
<ProductDetailContainer>
<ImageWrapper>
{image ? (
<img src={image} width={300} alt={name} />
) : category === CATEGORY_TYPE.FOOD ? (
<PreviewImage width={300} />
) : (
<PBPreviewImage width={300} />
)}
</ImageWrapper>
<ImageWrapper>{image ? <img src={image} width={300} alt={name} /> : <PreviewImage width={300} />}</ImageWrapper>
<DetailInfoWrapper>
<TagList tags={tags} />
<DescriptionWrapper>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Product/ProductList/ProductList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface ProductListProps {
sortOption?: SortOption;
}

const ProductList = ({ category, categoryId, sortOption }: ProductListProps) => {
const ProductList = ({ categoryId, sortOption }: ProductListProps) => {
const scrollRef = useRef<HTMLDivElement>(null);

const { fetchNextPage, hasNextPage, data } = useInfiniteProductsQuery(
Expand All @@ -32,7 +32,7 @@ const ProductList = ({ category, categoryId, sortOption }: ProductListProps) =>
<ul className={container}>
{products.map((product) => (
<li key={product.id}>
<Link to={`${PATH.PRODUCT_LIST}/${category}/${product.id}`}>
<Link to={`${PATH.PRODUCT_LIST}/detail/${product.id}`}>
<ProductItem product={product} />
</Link>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { style } from '@vanilla-extract/css';

export const container = style({
display: 'flex',
alignItems: 'center',
gap: 12,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Meta, StoryObj } from '@storybook/react';

import ProductOverviewList from './ProductOverviewList';

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

const meta: Meta<typeof ProductOverviewList> = {
title: 'product/ProductOverviewList',
component: ProductOverviewList,
args: {
products: mockProducts.recipes[0].products,
},
};

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

export const Default: Story = {};
27 changes: 27 additions & 0 deletions src/components/Product/ProductOverviewList/ProductOverviewList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Link } from 'react-router-dom';

import { container } from './productOverviewList.css';
import ProductOverviewItem from '../ProductOverviewItem/ProductOverviewItem';

import { PATH } from '@/constants/path';
import type { Product } from '@/types/product';

interface ProductOverviewListProps {
products: Product[];
}

const ProductOverviewList = ({ products }: ProductOverviewListProps) => {
return (
<ul className={container}>
{products.map(({ id, image, name, price, averageRating }) => (
<li key={id}>
<Link to={`${PATH.PRODUCT_LIST}/detail/${id}`}>
<ProductOverviewItem image={image} name={name} price={price} rate={averageRating} />
</Link>
</li>
))}
</ul>
);
};

export default ProductOverviewList;
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface ProductPreviewListProps {
categoryId: number;
}

const ProductPreviewList = ({ category, categoryId }: ProductPreviewListProps) => {
const ProductPreviewList = ({ categoryId }: ProductPreviewListProps) => {
// 정렬기준은 어떤걸로 할지
const { data } = useInfiniteProductsQuery(categoryId, 'reviewCount,desc');
const products = data.pages.flatMap((page) => page.products);
Expand All @@ -24,7 +24,7 @@ const ProductPreviewList = ({ category, categoryId }: ProductPreviewListProps) =
<ul className={container}>
{productToDisplay.map((product) => (
<li key={product.id}>
<Link to={`${PATH.PRODUCT_LIST}/${category}/${product.id}`}>
<Link to={`${PATH.PRODUCT_LIST}/detail/${product.id}`}>
<ProductItem product={product} />
</Link>
</li>
Expand Down
1 change: 1 addition & 0 deletions src/components/Product/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { default as ProductDetailItem } from './ProductDetailItem/ProductDetailI
export { default as ProductItem } from './ProductItem/ProductItem';
export { default as ProductList } from './ProductList/ProductList';
export { default as ProductOverviewItem } from './ProductOverviewItem/ProductOverviewItem';
export { default as ProductOverviewList } from './ProductOverviewList/ProductOverviewList';
export { default as ProductRecipeList } from './ProductRecipeList/ProductRecipeList';
export { default as ProductTitle } from './ProductTitle/ProductTitle';
export { default as ProductPreviewList } from './ProductPreviewList/ProductPreviewList';
4 changes: 2 additions & 2 deletions src/components/Rank/ProductRankingList/ProductRankingList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ const ProductRankingList = () => {

return (
<ul className={container}>
{productRankings.products.map(({ id, name, image, price, categoryType }, index) => (
{productRankings.products.map(({ id, name, image, price }, index) => (
<li key={id}>
<Link to={`${PATH.PRODUCT_LIST}/${categoryType}/${id}`} onClick={handleProductRankingLinkClick}>
<Link to={`${PATH.PRODUCT_LIST}/detail/${id}`} onClick={handleProductRankingLinkClick}>
<ProductRankingItem rank={index + 1} name={name} image={image} price={price} />
</Link>
</li>
Expand Down
6 changes: 3 additions & 3 deletions src/components/Rank/RecipeRankingItem/RecipeRankingItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { buttonWrapper, imageWrapper, recipeImage, recipeTitle, info } from './recipeRankingItem.css';

import { RecipeFavoriteButton } from '@/components/Recipe';
import { RECIPE_CARD_DEFAULT_IMAGE_URL } from '@/constants/image';
import type { RecipeRanking } from '@/types/ranking';
import { getRelativeDate } from '@/utils/date';

Expand All @@ -13,10 +14,9 @@ const RecipeRankingItem = ({ recipe }: RecipeRankingItemProps) => {

return (
<>
{/* 이미지 값을 필수값으로 받을지 선택값으로 받을지에 따라 타입 수정 (현재는 대체 이미지로 인해 'string|null'임*/}
<div className={imageWrapper}>
{image && <img className={recipeImage} src={image} alt={title} />}
<div className={buttonWrapper}>
<img className={recipeImage} src={image ?? RECIPE_CARD_DEFAULT_IMAGE_URL} alt={title} />
<div className={buttonWrapper} onClick={(e) => e.preventDefault()}>
<RecipeFavoriteButton recipeId={id} favorite={favorite} />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { style } from '@vanilla-extract/css';

export const imageWrapper = style({
position: 'relative',
width: 166,
height: 146,
});

export const recipeImage = style({
width: '100%',
height: '100%',
height: 'auto',
minWidth: 163,
borderRadius: '6px',
objectFit: 'cover',
aspectRatio: '1 / 1',
});

export const buttonWrapper = style({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { style } from '@vanilla-extract/css';

export const container = style({
display: 'flex',
justifyContent: 'space-between',
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gridAutoRows: 'auto',
columnGap: 10,
rowGap: 20,
flexWrap: 'wrap',
padding: '0 20px',
});
Loading

0 comments on commit 6c8ae2b

Please sign in to comment.