-
Notifications
You must be signed in to change notification settings - Fork 0
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
[FEAT] 필터칩 추가 #34
[FEAT] 필터칩 추가 #34
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
.filterChip { | ||
display: inline-flex; | ||
flex-direction: row; | ||
align-items: center; | ||
padding: 2px 6px 2px 10px; | ||
border-radius: 100px; | ||
margin: 5px; | ||
} | ||
|
||
.label { | ||
font-family: "Pretendard"; | ||
font-style: normal; | ||
font-weight: 500; | ||
font-size: 14px; | ||
line-height: 20px; | ||
color: #000000; | ||
margin-right: 6px; | ||
} | ||
|
||
.close { | ||
cursor: pointer; | ||
width: 18px; | ||
height: 18px; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
color: #73777f; | ||
border-radius: 50%; | ||
} | ||
|
||
.resetLabel { | ||
font-family: "Pretendard"; | ||
font-style: normal; | ||
font-weight: 500; | ||
font-size: 14px; | ||
line-height: 20px; | ||
color: #ba1a1a; | ||
margin-right: 6px; | ||
margin-left: 3px; | ||
} | ||
|
||
.resetIcon { | ||
width: 18px; | ||
height: 18px; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import React from "react"; | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { FilterChip } from "./FilterChip"; | ||
|
||
const meta = { | ||
title: "Components/FilterChip", | ||
component: FilterChip, | ||
parameters: { | ||
layout: "centered", | ||
}, | ||
tags: ["autodocs"], | ||
argTypes: {}, | ||
args: { | ||
label: "", | ||
onRemove: () => {}, | ||
}, | ||
} satisfies Meta<typeof FilterChip>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
label: "2024", | ||
onRemove: () => {}, | ||
}, | ||
render: (args) => ( | ||
<> | ||
<FilterChip {...args} label="2024" /> | ||
<FilterChip {...args} label="연구실" /> | ||
<FilterChip {...args} label="웹/어플리케이션" /> | ||
</> | ||
), | ||
}; | ||
|
||
export const Reset: Story = { | ||
args: { | ||
label: "전체해제", | ||
onRemove: () => {}, | ||
isReset: true, | ||
}, | ||
render: (args) => <FilterChip {...args} />, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React from "react"; | ||
import { render, screen, fireEvent } from "@/utils/test-utils"; | ||
import { FilterChip } from "./FilterChip"; | ||
import "@testing-library/jest-dom"; | ||
|
||
describe("FilterChip component", () => { | ||
it("renders correctly with the given label", () => { | ||
render(<FilterChip label="2024" onRemove={() => {}} />); | ||
expect(screen.getByText("2024")).toBeInTheDocument(); | ||
}); | ||
|
||
it("calls onRemove when close button is clicked", () => { | ||
const onRemove = jest.fn(); | ||
render(<FilterChip label="2024" onRemove={onRemove} />); | ||
fireEvent.click(screen.getByText("X")); | ||
expect(onRemove).toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
describe("FilterChipReset component", () => { | ||
it("renders correctly", () => { | ||
render(<FilterChip label="전체해제" onRemove={() => {}} isReset />); | ||
expect(screen.getByText("전체해제")).toBeInTheDocument(); | ||
}); | ||
|
||
it("does not show the close button", () => { | ||
render(<FilterChip label="전체해제" onRemove={() => {}} isReset />); | ||
expect(screen.queryByText("X")).toBeNull(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import ResetIcon from "./ResetIcon"; | ||
import classes from "./FilterChip.module.css"; | ||
|
||
type FilterChipProps = { | ||
label: string; | ||
onRemove: () => void; | ||
isReset?: boolean; | ||
}; | ||
|
||
const randomBackgroundColor = () => { | ||
const colors = ["#DFE2EB", "#D1E4FF", "#F3DAFF"]; | ||
return colors[Math.floor(Math.random() * colors.length)]; | ||
}; | ||
|
||
export function FilterChip({ label, onRemove, isReset = false }: FilterChipProps) { | ||
const [bgColor, setBgColor] = useState<string>(""); | ||
|
||
useEffect(() => { | ||
if (!isReset) { | ||
setBgColor(randomBackgroundColor()); | ||
} | ||
}, [isReset]); | ||
|
||
return ( | ||
<div className={classes.filterChip} style={{ backgroundColor: isReset ? "#DFE2EB" : bgColor }}> | ||
{!isReset && <span className={classes.label}>{label}</span>} | ||
{!isReset && ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
위와 같이 처리해도 괜찮을 것 같습니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tabler icon 적용하였고 resetchip class 새로 만들어 나누어 리턴하는 방식으로 수정했습니다 |
||
<span className={classes.close} onClick={onRemove}> | ||
X | ||
</span> | ||
)} | ||
{isReset && ( | ||
<> | ||
<ResetIcon /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 반영했습니다 |
||
<span className={classes.resetLabel}>{label}</span> | ||
</> | ||
)} | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tabler Icons를 사용하면 관리가 편할 것 같습니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tabler Icons를 적용하는 데에 여기를 참고해 작업해주시면 좋겠습니다! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React from "react"; | ||
|
||
const ResetIcon = () => ( | ||
<svg | ||
width="18" | ||
height="18" | ||
viewBox="0 0 18 18" | ||
fill="none" | ||
border-radius="50%" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<path d="M10.5 11.25L7.5 14.25L10.5 17.25" stroke="#BA1A1A" /> | ||
<path | ||
d="M4.45337 11.625C3.85857 10.5948 3.63128 9.39308 3.80875 8.21679C3.98622 7.0405 4.55791 5.95936 5.43018 5.15047C6.30245 4.34158 7.42357 3.85291 8.60989 3.76451C9.7962 3.67612 10.9774 3.99324 11.9599 4.66392C12.9424 5.3346 13.668 6.31908 14.0178 7.45608C14.3677 8.59308 14.321 9.81518 13.8855 10.9222C13.4499 12.0292 12.6513 12.9554 11.6205 13.5492C10.5897 14.143 9.38777 14.3691 8.21166 14.1905" | ||
stroke="#BA1A1A" | ||
stroke-linecap="round" | ||
/> | ||
</svg> | ||
); | ||
|
||
export default ResetIcon; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
backgroundColor와 color를
FilterChip
의 props로 받아오게 하면 좋을 것 같아요!클립 색상을 어떻게 설정해야 하는지는 추후 논의가 필요할 것 같네요..! 노션에 올려두겠습니다 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요건 그냥 랜덤으로 되게 두었습니다