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

페이지 UI: 검색 페이지 #104

Merged
merged 11 commits into from
Jan 21, 2024
2 changes: 0 additions & 2 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import Flex from '@shared/flex/Flex';
import Header from '@shared/header/Header';
import ProductArticle from '@shared/product-article/ProductArticle';
import Radio from '@shared/radio/Radio';
import SearchBar from '@shared/search-bar/SearchBar';
import Spacing from '@shared/spacing/Spacing';
import Text from '@shared/text/Text';

Expand Down Expand Up @@ -134,7 +133,6 @@ export default function Home() {
<main className={cx('mainContainer')}>
<div className={cx('searchBarWrapper')}>
<Spacing size={16} />
<SearchBar />
<Spacing size={24} />
</div>
<Banner bannerData={bannerData} />
Expand Down
7 changes: 7 additions & 0 deletions src/app/search/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function SearchLayout({ children }: { children: React.ReactNode }) {
return (
<div style={{ padding: '0 24px' }}>{children}</div>
);
}

export default SearchLayout;
14 changes: 14 additions & 0 deletions src/app/search/page.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.mainContainer {
.filterWrapper {
display: flex;
align-items: center;
justify-content: space-between;
margin: 13px 0 24px;
}

.productArticleContainer {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
}
99 changes: 99 additions & 0 deletions src/app/search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
'use client';

import { useState, useRef } from 'react';

import classNames from 'classnames/bind';

import Text from '@/components/shared/text/Text';
import Drawer from '@shared/drawer/Drawer';
import Dropdown from '@shared/dropdown/Dropdown';
import Header from '@shared/header/Header';
import ProductArticle from '@shared/product-article/ProductArticle';
import SearchBar from '@shared/search-bar/SearchBar';
import Spacing from '@shared/spacing/Spacing';

import styles from './page.module.scss';

const cx = classNames.bind(styles);
const productArticleData = [
{
brand: '카믹스',
category: '코팅제',
id: 1,
img: '/assets/profile.JPG',
name: '아머올 세차용품 스피드 왁스 스프레이 500ml스피드 왁스 스프레이 500ml',
warningLevel: 'warning',
},
{
brand: '카믹스',
category: '코팅제',
id: 2,
img: '/assets/profile.JPG',
name: '아머올 세차용품 스피드 왁스 스프레이 500ml스피드 왁스 스프레이 500ml',
warningLevel: 'warning',
},
{
brand: '카믹스',
category: '코팅제',
id: 3,
img: '/assets/profile.JPG',
name: '아머올 세차용품 스피드 왁스 스프레이 500ml스피드 왁스 스프레이 500ml',
warningLevel: 'warning',
},
{
brand: '카믹스',
category: '코팅제',
id: 4,
img: '/assets/profile.JPG',
name: '아머올 세차용품 스피드 왁스 스프레이 500ml스피드 왁스 스프레이 500ml',
warningLevel: 'warning',
},
];

const options = [
{ label: '조회순', value: '1' },
{ label: '위반제품순', value: '2' },
{ label: '최신순', value: '3' },
{ label: '추천순', value: '4' },
];

function SearchPage() {
const dropdownRef = useRef<HTMLInputElement>(null);

const [selectedLabel, setSelectedLabel] = useState(options[0].label);
const [isOpenFilterDrawer, setIsOpenFilterDrawer] = useState(false);

const handleFilterClick = () => {
setIsOpenFilterDrawer((prev) => { return !prev; });
};

return (
<>
<Header isDisplayLogo={false} displayRightIconType="filter" onFilterClick={handleFilterClick} />
<Spacing size={8} />
<main className={cx('mainContainer')}>
<SearchBar />
<div className={cx('filterWrapper')}>
<Text typography="t6" color="gray300">{`총 ${productArticleData.length}개`}</Text>
<Dropdown
options={options}
selectedLabel={selectedLabel}
type="favorite"
ref={dropdownRef}
setSelectedLabel={setSelectedLabel}
/>
</div>
<div className={cx('productArticleContainer')}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

ProductArticle 컴포넌트에 box-shadow 스타일 추가해주세요!

스크린샷 2024-01-21 오후 3 36 52

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정했습니다!

{productArticleData.map((item) => {
return <ProductArticle key={item.id} itemData={item} />;
})}
</div>
</main>
<Drawer isOpen={isOpenFilterDrawer} onClose={() => { setIsOpenFilterDrawer(false); }}>
{/* 필터 내용 아코디언 */}
<p>Filter Content</p>
</Drawer>
</>
);
}
export default SearchPage;
18 changes: 7 additions & 11 deletions src/components/icons/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@ interface FilterProps {
width?: number
height?: number
color?: Colors
onClick?: () => void
}

function Filter({ width = 18, height = 16, color = 'gray200' }: FilterProps) {
function Filter({
width = 18, height = 16, color = 'gray400', onClick,
}: FilterProps) {
return (
<svg width={width} height={height} viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.1875 2.75H5.5C5.31766 2.75 5.1428 2.67757 5.01386 2.54864C4.88493 2.4197 4.8125 2.24484 4.8125 2.0625C4.8125 1.88016 4.88493 1.7053 5.01386 1.57636C5.1428 1.44743 5.31766 1.375 5.5 1.375H17.1875C17.3698 1.375 17.5447 1.44743 17.6736 1.57636C17.8026 1.7053 17.875 1.88016 17.875 2.0625C17.875 2.24484 17.8026 2.4197 17.6736 2.54864C17.5447 2.67757 17.3698 2.75 17.1875 2.75Z" fill={colors[color]} />
<path d="M2.75 2.75H0.6875C0.505164 2.75 0.330295 2.67757 0.201364 2.54864C0.0724328 2.4197 0 2.24484 0 2.0625C0 1.88016 0.0724328 1.7053 0.201364 1.57636C0.330295 1.44743 0.505164 1.375 0.6875 1.375H2.75C2.93234 1.375 3.1072 1.44743 3.23614 1.57636C3.36507 1.7053 3.4375 1.88016 3.4375 2.0625C3.4375 2.24484 3.36507 2.4197 3.23614 2.54864C3.1072 2.67757 2.93234 2.75 2.75 2.75Z" fill={colors[color]} />
<path d="M12.375 8.25H0.6875C0.505164 8.25 0.330295 8.17757 0.201364 8.04864C0.0724328 7.91971 0 7.74484 0 7.5625C0 7.38016 0.0724328 7.2053 0.201364 7.07636C0.330295 6.94743 0.505164 6.875 0.6875 6.875H12.375C12.5573 6.875 12.7322 6.94743 12.8611 7.07636C12.9901 7.2053 13.0625 7.38016 13.0625 7.5625C13.0625 7.74484 12.9901 7.91971 12.8611 8.04864C12.7322 8.17757 12.5573 8.25 12.375 8.25Z" fill={colors[color]} />
<path d="M5.5 13.75H0.6875C0.505164 13.75 0.330295 13.6776 0.201364 13.5486C0.0724328 13.4197 0 13.2448 0 13.0625C0 12.8802 0.0724328 12.7053 0.201364 12.5764C0.330295 12.4474 0.505164 12.375 0.6875 12.375H5.5C5.68234 12.375 5.8572 12.4474 5.98614 12.5764C6.11507 12.7053 6.1875 12.8802 6.1875 13.0625C6.1875 13.2448 6.11507 13.4197 5.98614 13.5486C5.8572 13.6776 5.68234 13.75 5.5 13.75Z" fill={colors[color]} />
<path d="M4.125 4.125C3.71708 4.125 3.31831 4.00404 2.97914 3.77741C2.63996 3.55078 2.37561 3.22866 2.2195 2.85179C2.06339 2.47491 2.02255 2.06021 2.10213 1.66013C2.18171 1.26004 2.37815 0.892539 2.66659 0.604093C2.95504 0.315647 3.32254 0.119213 3.72263 0.0396313C4.12271 -0.0399507 4.53741 0.000893652 4.91429 0.156999C5.29116 0.313105 5.61328 0.577461 5.83991 0.916637C6.06654 1.25581 6.1875 1.65458 6.1875 2.0625C6.1875 2.60951 5.9702 3.13412 5.58341 3.52091C5.19662 3.9077 4.67201 4.125 4.125 4.125ZM4.125 1.375C3.98903 1.375 3.8561 1.41532 3.74305 1.49087C3.62999 1.56641 3.54187 1.67378 3.48983 1.79941C3.4378 1.92503 3.42418 2.06326 3.45071 2.19663C3.47724 2.32999 3.54272 2.45249 3.63887 2.54864C3.73501 2.64479 3.85751 2.71026 3.99088 2.73679C4.12424 2.76332 4.26247 2.7497 4.3881 2.69767C4.51372 2.64563 4.62109 2.55751 4.69664 2.44446C4.77218 2.3314 4.8125 2.19848 4.8125 2.0625C4.8125 1.88016 4.74007 1.7053 4.61114 1.57637C4.48221 1.44743 4.30734 1.375 4.125 1.375Z" fill={colors[color]} />
<path d="M13.75 9.625C13.3421 9.625 12.9433 9.50404 12.6041 9.27741C12.265 9.05078 12.0006 8.72866 11.8445 8.35179C11.6884 7.97491 11.6475 7.56021 11.7271 7.16013C11.8067 6.76004 12.0031 6.39254 12.2916 6.10409C12.58 5.81565 12.9475 5.61921 13.3476 5.53963C13.7477 5.46005 14.1624 5.50089 14.5393 5.657C14.9162 5.81311 15.2383 6.07746 15.4649 6.41664C15.6915 6.75581 15.8125 7.15458 15.8125 7.5625C15.8125 8.10951 15.5952 8.63412 15.2084 9.02091C14.8216 9.4077 14.297 9.625 13.75 9.625ZM13.75 6.875C13.614 6.875 13.4811 6.91532 13.368 6.99087C13.255 7.06641 13.1669 7.17378 13.1148 7.29941C13.0628 7.42503 13.0492 7.56326 13.0757 7.69663C13.1022 7.82999 13.1677 7.95249 13.2639 8.04864C13.36 8.14479 13.4825 8.21026 13.6159 8.23679C13.7492 8.26332 13.8875 8.2497 14.0131 8.19767C14.1387 8.14563 14.2461 8.05751 14.3216 7.94446C14.3972 7.8314 14.4375 7.69848 14.4375 7.5625C14.4375 7.38016 14.3651 7.2053 14.2361 7.07637C14.1072 6.94743 13.9323 6.875 13.75 6.875Z" fill={colors[color]} />
<path d="M6.875 15.125C6.46708 15.125 6.06831 15.004 5.72914 14.7774C5.38996 14.5508 5.12561 14.2287 4.9695 13.8518C4.81339 13.4749 4.77255 13.0602 4.85213 12.6601C4.93171 12.26 5.12815 11.8925 5.41659 11.6041C5.70504 11.3156 6.07254 11.1192 6.47263 11.0396C6.87271 10.96 7.28741 11.0009 7.66429 11.157C8.04116 11.3131 8.36328 11.5775 8.58991 11.9166C8.81654 12.2558 8.9375 12.6546 8.9375 13.0625C8.9375 13.6095 8.7202 14.1341 8.33341 14.5209C7.94662 14.9077 7.42201 15.125 6.875 15.125ZM6.875 12.375C6.73903 12.375 6.60611 12.4153 6.49305 12.4909C6.37999 12.5664 6.29187 12.6738 6.23983 12.7994C6.1878 12.925 6.17418 13.0633 6.20071 13.1966C6.22724 13.33 6.29272 13.4525 6.38887 13.5486C6.48501 13.6448 6.60751 13.7103 6.74088 13.7368C6.87424 13.7633 7.01247 13.7497 7.1381 13.6977C7.26372 13.6456 7.37109 13.5575 7.44664 13.4445C7.52218 13.3314 7.5625 13.1985 7.5625 13.0625C7.5625 12.8802 7.49007 12.7053 7.36114 12.5764C7.23221 12.4474 7.05734 12.375 6.875 12.375Z" fill={colors[color]} />
<path d="M17.1875 8.25H15.125C14.9427 8.25 14.7678 8.17757 14.6389 8.04864C14.5099 7.91971 14.4375 7.74484 14.4375 7.5625C14.4375 7.38016 14.5099 7.2053 14.6389 7.07636C14.7678 6.94743 14.9427 6.875 15.125 6.875H17.1875C17.3698 6.875 17.5447 6.94743 17.6736 7.07636C17.8026 7.2053 17.875 7.38016 17.875 7.5625C17.875 7.74484 17.8026 7.91971 17.6736 8.04864C17.5447 8.17757 17.3698 8.25 17.1875 8.25Z" fill={colors[color]} />
<path d="M17.1875 13.75H8.25C8.06766 13.75 7.8928 13.6776 7.76386 13.5486C7.63493 13.4197 7.5625 13.2448 7.5625 13.0625C7.5625 12.8802 7.63493 12.7053 7.76386 12.5764C7.8928 12.4474 8.06766 12.375 8.25 12.375H17.1875C17.3698 12.375 17.5447 12.4474 17.6736 12.5764C17.8026 12.7053 17.875 12.8802 17.875 13.0625C17.875 13.2448 17.8026 13.4197 17.6736 13.5486C17.5447 13.6776 17.3698 13.75 17.1875 13.75Z" fill={colors[color]} />
<svg width={width} height={height} viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg" onClick={onClick}>
<path d="M8 12C7.71667 12 7.47917 11.9042 7.2875 11.7125C7.09583 11.5208 7 11.2833 7 11C7 10.7167 7.09583 10.4792 7.2875 10.2875C7.47917 10.0958 7.71667 10 8 10H10C10.2833 10 10.5208 10.0958 10.7125 10.2875C10.9042 10.4792 11 10.7167 11 11C11 11.2833 10.9042 11.5208 10.7125 11.7125C10.5208 11.9042 10.2833 12 10 12H8ZM4 7C3.71667 7 3.47917 6.90417 3.2875 6.7125C3.09583 6.52083 3 6.28333 3 6C3 5.71667 3.09583 5.47917 3.2875 5.2875C3.47917 5.09583 3.71667 5 4 5H14C14.2833 5 14.5208 5.09583 14.7125 5.2875C14.9042 5.47917 15 5.71667 15 6C15 6.28333 14.9042 6.52083 14.7125 6.7125C14.5208 6.90417 14.2833 7 14 7H4ZM1 2C0.716667 2 0.479167 1.90417 0.2875 1.7125C0.0958333 1.52083 0 1.28333 0 1C0 0.716667 0.0958333 0.479167 0.2875 0.2875C0.479167 0.0958333 0.716667 0 1 0H17C17.2833 0 17.5208 0.0958333 17.7125 0.2875C17.9042 0.479167 18 0.716667 18 1C18 1.28333 17.9042 1.52083 17.7125 1.7125C17.5208 1.90417 17.2833 2 17 2H1Z" fill={colors[color]} />
</svg>

);
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/icons/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ interface SearchProps {
color?: Colors
}

function Search({ size = 18, color = 'black' }: SearchProps) {
function Search({ size = 17.5, color = 'tertiary400' }: SearchProps) {
return (

<svg width={size} height={size} viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down
2 changes: 1 addition & 1 deletion src/components/shared/dropdown/Dropdown.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

&.favorite {
width: 80px;
padding: 4px 4px 4px 8px;
padding: 4px 8px;
border-radius: 8px;
background-color: var(--tertiary-200);
}
Expand Down
17 changes: 16 additions & 1 deletion src/components/shared/dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Story = StoryObj<typeof meta>;
export const YoutubeVideo: Story = {
args: {
type: 'favorite',
label: '최신순',
selectedLabel: '최신순',
options: [
{ label: '최신순', value: 'latest' },
{ label: '오래된순', value: 'oldest' },
Expand All @@ -27,3 +27,18 @@ export const YoutubeVideo: Story = {
value: 'latest',
},
};

export const SearchProduct: Story = {
args: {
type: 'favorite',
selectedLabel: '조회순',
options: [
{ label: '조회순', value: 'Viewed' },
{ label: '위반제품순', value: 'Violated' },
{ label: '최신순', value: 'latest' },
{ label: '추천순', value: 'Recommend' },
],
placeholder: '조회순',
value: 'Viewed',
},
};
32 changes: 26 additions & 6 deletions src/components/shared/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ interface Option {

interface DropdownProps extends InputHTMLAttributes<HTMLInputElement> {
options: Option[]
label: string | number
value: string | number
selectedLabel: string | number
value?: string | number
type: 'favorite'
setSelectedLabel: React.Dispatch<React.SetStateAction<string>>
}

const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(({
label,
selectedLabel,
type,
options,
value,
setSelectedLabel,
...props
}, ref) => {
const [isOpen, setIsOpen] = useState(false);
Expand All @@ -41,21 +43,39 @@ const Dropdown = forwardRef<HTMLInputElement, DropdownProps>(({
setIsOpen(false);
};

const handleLabelClick = (newLabel: string) => {
setSelectedLabel(() => { return newLabel; });
closeDropdownMenu();
};

const containerRef = useOutsideClick(closeDropdownMenu);

return (
<div className={cx('container', { [type]: true })} ref={containerRef}>
<button onClick={openDropdownMenu} className={cx('selectedValue', { [type]: true })}>
<Text typography="t6" color="tertiary400">{label}</Text>
<Text typography="t6" color="tertiary400">{selectedLabel}</Text>
<Expand isRotate={isOpen} color="tertiary400" />
</button>
{isOpen && (
<ul className={cx('menu', { [type]: true })}>
{options.map((option) => {
return (
<li key={option.value} className={cx('item', { [type]: true })}>
<input className={cx('input')} id={option.label} type="radio" ref={ref} value={value} {...props} />
<label className={cx('label', { [type]: true })} htmlFor={option.label} onClick={closeDropdownMenu} role="presentation">
<input
className={cx('input')}
id={option.label}
type="radio"
ref={ref}
value={option.value}
checked={selectedLabel === option.label}
{...props}
/>
<label
className={cx('label', { [type]: true })}
htmlFor={option.label}
onClick={() => { return handleLabelClick(option.label); }}
role="presentation"
>
{option.label}
</label>
</li>
Expand Down
3 changes: 2 additions & 1 deletion src/components/shared/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { HeaderProps } from './types/headerType';

export default function Header({
isDisplayLogo = true, className,
children, isTransparent = false, displayRightIconType,
children, isTransparent = false, displayRightIconType, onFilterClick,
}:HeaderProps) {
const cx = classNames.bind(styles);

Expand All @@ -18,6 +18,7 @@ export default function Header({
<RightIcon
className={cx('right')}
displayRightIconType={displayRightIconType}
onFilterClick={onFilterClick}
/>
</ul>
</nav>
Expand Down
12 changes: 11 additions & 1 deletion src/components/shared/header/headerItems/RightIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useState } from 'react';
import Link from 'next/link';

import FilledHeart from '@components/icons/FilledHeart';
import Filter from '@components/icons/Filter';
import Heart from '@components/icons/Heart';
import Search from '@components/icons/Search';
import Share from '@components/icons/Share';
Expand All @@ -13,14 +14,23 @@ import { RightIconProps } from '../types/headerType';

function RightIcon({
className,
displayRightIconType,
displayRightIconType, onFilterClick,
}: RightIconProps) {
const [isSaved, setIsSaved] = useState(false);

const handleHeartClick = () => {
setIsSaved((prev) => { return !prev; });
};

if (displayRightIconType === 'filter') {
return (
<li className={className}>
{/* 필터가 적용됐을 때만 필터 아이콘이 바뀜 */}
<Filter onClick={onFilterClick} />
</li>
);
}

if (displayRightIconType === 'search') {
return (
<li className={className}>
Expand Down
3 changes: 2 additions & 1 deletion src/components/shared/header/types/headerType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ interface LeftIconProps {
interface RightIconProps {
className?: string;
displayRightIconType?:string;

onFilterClick?: () => void;
}

interface HeaderProps extends LeftIconProps {
isTransparent?: boolean;
displayRightIconType?:string;
onFilterClick?: () => void;
}

export type { HeaderProps, LeftIconProps, RightIconProps };
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
flex-direction: column;
width: 100%;
overflow: hidden;
border: 1px solid var(--gray);
border-radius: 15px;
box-shadow: 0 0 0 1px var(--gray);
box-shadow: 0 4px 7px 1px rgba($color: #000, $alpha: 5%);

.imgBox {
height: 100px;
Expand All @@ -16,8 +17,8 @@

.icon {
position: absolute;
top: 10px;
left: 10px;
top: 8px;
right: 8px;
}
}

Expand Down
Loading
Loading