Skip to content

Commit

Permalink
feat: 꿀조합 검색 디자인 변경점 적용 (#91)
Browse files Browse the repository at this point in the history
* fix: 폴더명 변경

* refactor: RecipeSearchResultList -> RecipeSearchResultPreviewList로 이름 변경

* feat: 검색 꿀조합 목록 페이지 추가

* style: RecipeSearchResultPreviewList으로 컴포넌트 변경

* feat: 꿀조합 미리보기 개수를 4개로 수정

* refactor: DefaultRecipeItem 컴포넌트로 교체

* feat: 전체보기 버튼 스타일 수정

* fix: 꿀조합 페이지로 이동하지 않는 문제 해결

* feat: 불필요한 Link 제거

* feat: PageHeader 컴포넌트를 TopBar 컴포넌트로 교체

* refactor: 전체보기 버튼 컴포넌트 추가

* fix: 헤더 디자인 잘못된 부분 수정
  • Loading branch information
xodms0309 authored Apr 19, 2024
1 parent 12e792f commit f751e9e
Show file tree
Hide file tree
Showing 18 changed files with 150 additions and 68 deletions.
25 changes: 25 additions & 0 deletions src/components/Common/ShowAllButton/ShowAllButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Link } from 'react-router-dom';

import { moreIconWrapper, linkWrapper } from './showAllButton.css';

import { SvgIcon, Text } from '@/components/Common';
import { vars } from '@/styles/theme.css';

interface ShowAllButtonProps {
link: string;
}

const ShowAllButton = ({ link }: ShowAllButtonProps) => {
return (
<Link to={link} className={linkWrapper}>
<div className={moreIconWrapper}>
<SvgIcon variant="arrowRight" fill="none" stroke={vars.colors.gray5} />
</div>
<Text as="span" color="info" weight="semiBold" size="caption2">
전체보기
</Text>
</Link>
);
};

export default ShowAllButton;
20 changes: 20 additions & 0 deletions src/components/Common/ShowAllButton/showAllButton.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { vars } from '@/styles/theme.css';
import { style } from '@vanilla-extract/css';

export const linkWrapper = style({
display: 'flex',
flexDirection: 'column',
gap: 12,
alignItems: 'center',
width: 45,
});

export const moreIconWrapper = style({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: 40,
height: 40,
borderRadius: '50%',
background: vars.colors.secondary1,
});
2 changes: 2 additions & 0 deletions src/components/Common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ 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';
export { default as TopBar } from './TopBar/TopBar';
export { default as ShowAllButton } from './ShowAllButton/ShowAllButton';
21 changes: 6 additions & 15 deletions src/components/Product/ProductRecipeList/ProductRecipeList.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { Link } from 'react-router-dom';
import { container, moreItem } from './productRecipeList.css';

import { container, moreIcon, moreIconWrapper, moreItem, moreLink } from './productRecipeList.css';

import { SvgIcon, Text } from '@/components/Common';
import { ShowAllButton } from '@/components/Common';
import { DefaultRecipeItem } from '@/components/Recipe';
import { PATH } from '@/constants/path';
import { useInfiniteProductRecipesQuery } from '@/hooks/queries/product';
import { vars } from '@/styles/theme.css';
import displaySlice from '@/utils/displaySlice';

interface ProductRecipeListProps {
productId: number;
productName: string;
}

const ProductRecipeList = ({ productId }: ProductRecipeListProps) => {
const ProductRecipeList = ({ productId, productName }: ProductRecipeListProps) => {
// 상품에서 보여줄 꿀조합 정렬 조건
const { data } = useInfiniteProductRecipesQuery(productId, 'favoriteCount,desc');

Expand All @@ -32,15 +31,7 @@ const ProductRecipeList = ({ productId }: ProductRecipeListProps) => {
))}
{recipeToDisplay.length < recipes.length && (
<li className={moreItem}>
{/*링크는 상품이 포함된 꿀조합 검색결과로 가는 것이 맞을듯?*/}
<Link to={''} className={moreLink}>
<div className={moreIconWrapper}>
<SvgIcon variant="arrowLeft" className={moreIcon} fill="none" stroke={vars.colors.gray5} />
</div>
<Text as="span" color="info" weight="semiBold" size="caption2">
전체보기
</Text>
</Link>
<ShowAllButton link={`${PATH.SEARCH}/recipes?query=${productName}`} />
</li>
)}
</ul>
Expand Down
23 changes: 0 additions & 23 deletions src/components/Product/ProductRecipeList/productRecipeList.css.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { vars } from '@/styles/theme.css';
import { style } from '@vanilla-extract/css';

export const container = style({
Expand All @@ -14,25 +13,3 @@ export const moreItem = style({
alignItems: 'center',
minWidth: 108,
});

export const moreLink = style({
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
});

export const moreIconWrapper = style({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: 40,
height: 40,
marginBottom: 12,
borderRadius: '50%',
background: vars.colors.secondary1,
});

export const moreIcon = style({
transform: 'rotate(180deg)',
});
3 changes: 2 additions & 1 deletion src/components/Recipe/RecipeItem/RecipeItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
RECIPE_CARD_DEFAULT_IMAGE_URL_4,
RECIPE_CARD_DEFAULT_IMAGE_URL_5,
} from '@/constants/image';
import { PATH } from '@/constants/path';
import RecipeItemProvider from '@/contexts/RecipeItemContext';
import { useRecipeItemValueContext } from '@/hooks/context';
import type { Recipe } from '@/types/recipe';
Expand All @@ -50,7 +51,7 @@ const RecipeItem = ({ recipe, children }: RecipeItemProps) => {

return (
<RecipeItemProvider recipe={recipe}>
<Link to={`${id}`}>{children}</Link>
<Link to={`${PATH.RECIPE}/${id}`}>{children}</Link>
</RecipeItemProvider>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useRef } from 'react';

import { listWrapper } from './recipeSearchResultPreviewList.css';
import SearchNotFound from '../SearchNotFound/SearchNotFound';

import { ShowAllButton } from '@/components/Common';
import { DefaultRecipeItem } from '@/components/Recipe';
import { PATH } from '@/constants/path';
import { useIntersectionObserver } from '@/hooks/common';
import { useInfiniteRecipeSearchResultsQuery } from '@/hooks/queries/search';
import displaySlice from '@/utils/displaySlice';

interface RecipeSearchResultPreviewListProps {
searchQuery: string;
}

const RecipeSearchResultPreviewList = ({ searchQuery }: RecipeSearchResultPreviewListProps) => {
const { data: searchResponse, fetchNextPage, hasNextPage } = useInfiniteRecipeSearchResultsQuery(searchQuery);
const scrollRef = useRef<HTMLDivElement>(null);
useIntersectionObserver<HTMLDivElement>(fetchNextPage, scrollRef, hasNextPage);

const recipes = searchResponse.pages.flatMap((page) => page.recipes);

if (recipes.length === 0) {
return <SearchNotFound />;
}

return (
<ul className={listWrapper}>
{displaySlice(false, recipes, 4).map((recipe, idx) => (
<li key={recipe.id}>
{idx < 4 ? (
<DefaultRecipeItem recipe={recipe} />
) : (
<ShowAllButton link={`${PATH.SEARCH}/recipes?query=${searchQuery}`} />
)}
</li>
))}
</ul>
);
};

export default RecipeSearchResultPreviewList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { style } from '@vanilla-extract/css';

export const listWrapper = style({
display: 'flex',
gap: 10,
alignItems: 'center',
overflowY: 'scroll',
});
4 changes: 2 additions & 2 deletions src/components/Search/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { default as ProductSearchResultPreviewList } from './ProductSearchResultList/ProductSearchResultPreviewList';
export { default as ProductSearchResultPreviewList } from './ProductSearchResultPreviewList/ProductSearchResultPreviewList';
export { default as RecommendList } from './RecommendList/RecommendList';
export { default as RecipeSearchResultList } from './RecipeSearchResultList/RecipeSearchResultList';
export { default as RecipeSearchResultPreviewList } from './RecipeSearchResultPreviewList/RecipeSearchResultPreviewList';
export { default as TagSearchResultList } from './TagSearchResultList/TagSearchResultList';
export { default as SearchInput } from './SearchInput/SearchInput';
2 changes: 1 addition & 1 deletion src/pages/ProductDetailPage/ProductDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const ProductDetailPage = () => {
<div style={{ height: '24px' }} />
<ErrorBoundary fallback={ErrorComponent} handleReset={reset}>
<Suspense fallback={<Loading />}>
<ProductRecipeList productId={Number(productId)} />
<ProductRecipeList productId={Number(productId)} productName={productDetail.name} />
</Suspense>
</ErrorBoundary>
</section>
Expand Down
8 changes: 6 additions & 2 deletions src/pages/ProductSearchListPage/ProductSearchListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom';

import { container } from './productSearchListPage.css';

import { PageHeader } from '@/components/Common';
import { TopBar } from '@/components/Common';
import { ProductOverviewList } from '@/components/Product';
import { useIntersectionObserver } from '@/hooks/common';
import { useInfiniteProductSearchResultsQuery } from '@/hooks/queries/search';
Expand All @@ -24,7 +24,11 @@ export const ProductSearchListPage = () => {

return (
<>
<PageHeader title={`'${searchQuery}'이/가 포함된 상품`} hasBackLink />
<TopBar>
<TopBar.BackLink />
<TopBar.Title title={`'${searchQuery}'이/가 포함된 상품`} />
<TopBar.Spacer />
</TopBar>
<div className={container}>
<ProductOverviewList products={products} hasBorder />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { useRef } from 'react';
import { Link } from 'react-router-dom';
import { styled } from 'styled-components';
import { useSearchParams } from 'react-router-dom';

import SearchNotFound from '../SearchNotFound/SearchNotFound';
import { listWrapper } from './recipeSearchListPage.css';

import { RecipeItem } from '@/components/Recipe';
import { PATH } from '@/constants/path';
import { TopBar } from '@/components/Common';
import { DefaultRecipeItem } from '@/components/Recipe';
import SearchNotFound from '@/components/Search/SearchNotFound/SearchNotFound';
import { useIntersectionObserver } from '@/hooks/common';
import { useInfiniteRecipeSearchResultsQuery } from '@/hooks/queries/search';

interface RecipeSearchResultListProps {
searchQuery: string;
}
export const RecipeSearchListPage = () => {
const [searchParams, setSearchParams] = useSearchParams();
const searchQuery = searchParams.get('query') || '';

const RecipeSearchResultList = ({ searchQuery }: RecipeSearchResultListProps) => {
const { data: searchResponse, fetchNextPage, hasNextPage } = useInfiniteRecipeSearchResultsQuery(searchQuery);
const scrollRef = useRef<HTMLDivElement>(null);
useIntersectionObserver<HTMLDivElement>(fetchNextPage, scrollRef, hasNextPage);
Expand All @@ -26,24 +25,19 @@ const RecipeSearchResultList = ({ searchQuery }: RecipeSearchResultListProps) =>

return (
<>
<RecipeSearchResultListContainer>
<TopBar>
<TopBar.BackLink />
<TopBar.Title title={`'${searchQuery}'이/가 포함된 꿀조합`} />
<TopBar.Spacer />
</TopBar>
<ul className={listWrapper}>
{recipes.map((recipe) => (
<li key={recipe.id}>
<Link to={`${PATH.RECIPE}/${recipe.id}`}>
<RecipeItem recipe={recipe} />
</Link>
<DefaultRecipeItem recipe={recipe} />
</li>
))}
</RecipeSearchResultListContainer>
</ul>
<div ref={scrollRef} aria-hidden />
</>
);
};

export default RecipeSearchResultList;

const RecipeSearchResultListContainer = styled.ul`
& > li + li {
margin-top: 40px;
}
`;
8 changes: 8 additions & 0 deletions src/pages/RecipeSearchListPage/recipeSearchListPage.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { style } from '@vanilla-extract/css';

export const listWrapper = style({
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: '16px 10px',
padding: '0 20px',
});
4 changes: 2 additions & 2 deletions src/pages/SearchPage/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { badgeContainer, searchWrapper, searchResultTitle, searchSection, subTit
import { Text, Badge, ErrorBoundary, ErrorComponent, Loading, PageHeader } from '@/components/Common';
import {
ProductSearchResultPreviewList,
RecipeSearchResultList,
RecipeSearchResultPreviewList,
RecommendList,
SearchInput,
} from '@/components/Search';
Expand Down Expand Up @@ -87,7 +87,7 @@ export const SearchPage = () => {
</Text>
<ErrorBoundary fallback={ErrorComponent}>
<Suspense fallback={<Loading />}>
<RecipeSearchResultList searchQuery={searchQuery} />
<RecipeSearchResultPreviewList searchQuery={searchQuery} />
</Suspense>
</ErrorBoundary>
</div>
Expand Down
9 changes: 9 additions & 0 deletions src/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ const router = createBrowserRouter([
return { Component: ProductSearchListPage };
},
},
{
path: `${PATH.SEARCH}/recipes`,
async lazy() {
const { RecipeSearchListPage } = await import(
/* webpackChunkName: "RecipeSearchListPage" */ '@/pages/RecipeSearchListPage/RecipeSearchListPage'
);
return { Component: RecipeSearchListPage };
},
},
],
},
]);
Expand Down

0 comments on commit f751e9e

Please sign in to comment.