Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
31d1ee3
feat: 하트 아웃라인 아이콘 추가
YeBeenChoi Jan 19, 2026
f622c6f
feat: 하트 필드 아이콘 추가
YeBeenChoi Jan 19, 2026
feeefd4
chore: 하트 아이콘 export 추가
YeBeenChoi Jan 19, 2026
a976a9b
chore: 공용 아이콘 export 정리
YeBeenChoi Jan 19, 2026
3b14eb3
feat: FavoriteButton 컴포넌트 구현
YeBeenChoi Jan 19, 2026
7fbbe5a
feat: FavoriteButton 스타일 variants 추가
YeBeenChoi Jan 19, 2026
73a9922
chore: FavoriteButton export 추가
YeBeenChoi Jan 19, 2026
ada484d
feat: Playground에 FavoriteButton 예시 추가
YeBeenChoi Jan 19, 2026
062c06b
chore: SearchBar export 정리
YeBeenChoi Jan 19, 2026
fb0064e
chore: 공용 아이콘 export 수정
YeBeenChoi Jan 19, 2026
870e954
refactor: FavoriteButton Props 타입 분리
YeBeenChoi Jan 20, 2026
65e84eb
chore: FavoriteButton export 추가
YeBeenChoi Jan 20, 2026
6bbfc5e
refactor: 하트 아이콘 currentColor 적용
YeBeenChoi Jan 20, 2026
917e64e
refactor: 하트 필드 아이콘 제거
YeBeenChoi Jan 20, 2026
d7339ee
chore: 하트 아이콘 export 정리
YeBeenChoi Jan 20, 2026
34491c4
chore: 공용 아이콘 export 정리
YeBeenChoi Jan 20, 2026
986b8f4
refactor: FavoriteButton 아이콘 색상 상태 처리 개선
YeBeenChoi Jan 20, 2026
44a1922
refactor: FavoriteButton 아이콘 색상 스타일 정리
YeBeenChoi Jan 20, 2026
83aa825
refactor: 하트 아이콘 변수 기반 fill/stroke 적용
YeBeenChoi Jan 20, 2026
a52581f
feat: FavoriteButton variant 옵션 추가
YeBeenChoi Jan 20, 2026
02dd1bd
feat: FavoriteButton default/inverse 스타일 추가
YeBeenChoi Jan 20, 2026
43a694e
feat: Playground에 FavoriteButton inverse 예시 추가
YeBeenChoi Jan 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/pages/playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BannerCard } from '@shared/ui/BannerCard/BannerCard';
import { Button } from '@shared/ui/Button/Button';
import { Card } from '@shared/ui/Card/Card';
import { Checkbox } from '@shared/ui/Checkbox/Checkbox';
import { FavoriteButton } from '@shared/ui/FavoriteButton';
import { Header } from '@shared/ui/Header/Header';
import { Modal } from '@shared/ui/Modal/Modal';
import { Profile } from '@shared/ui/Profile/Profile';
Expand Down Expand Up @@ -121,6 +122,16 @@ export default function Playground() {
<h2 className="typo-body-1">SearchBar</h2>
<SearchBar placeholder="어떤 제품을 찾으시나요?" onSearch={() => {}} />
</section>
{/* Favorite Button */}
<section className="flex flex-col gap-4">
<h2 className="typo-body-1">FavoriteButton</h2>
<div className="flex items-center gap-4">
<FavoriteButton />
<div className="rounded-full bg-[var(--color-black)] p-2">
<FavoriteButton variant="inverse" />
</div>
</div>
</section>
{/* BannerCard */}
<section className="flex flex-col gap-4">
<h2 className="typo-body-1">Banner Card</h2>
Expand Down
3 changes: 3 additions & 0 deletions src/shared/assets/icons/common/heart-outline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/shared/assets/icons/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as CaretDownMdIcon } from './caret-down-md.svg?react';
export { default as CheckIcon } from './check.svg?react';
export { default as DoneIcon } from './done.svg?react';
export { default as SearchMagnifyingGlassIcon } from './search-magnifying-glass.svg?react';
export { default as HeartIcon } from './heart-outline.svg?react';
2 changes: 1 addition & 1 deletion src/shared/assets/icons/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { CaretDownMdIcon, CheckIcon, DoneIcon, SearchMagnifyingGlassIcon } from './common';
export { CaretDownMdIcon, CheckIcon, DoneIcon, HeartIcon, SearchMagnifyingGlassIcon } from './common';
export { GearIcon, ShoppingIcon, SellIcon } from './banner';
47 changes: 47 additions & 0 deletions src/shared/ui/FavoriteButton/FavoriteButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { HeartIcon } from '@shared/assets/icons';
import clsx from 'clsx';
import { useState } from 'react';
import { favoriteButtonVariants } from './FavoriteButton.variants';

export interface FavoriteButtonProps {
defaultActive?: boolean;
onToggle?: (isActive: boolean) => void;
ariaLabel?: string;
variant?: 'default' | 'inverse';
}

export const FavoriteButton = ({
defaultActive = false,
onToggle,
ariaLabel = '찜',
variant = 'default',
}: FavoriteButtonProps) => {
const [isActive, setActive] = useState<boolean>(defaultActive);

const styles = favoriteButtonVariants({ variant });

const handleClick = () => {
const nextActive = !isActive;
setActive(nextActive);
onToggle?.(nextActive);
};

const iconStateClassName = clsx(
'fill-[var(--icon-fill)]',
'stroke-[var(--icon-stroke)]',
isActive ? '[--icon-fill:var(--icon-fill-active)]' : '[--icon-fill:transparent]',
'group-focus-visible:[--icon-fill:var(--icon-fill-active)]'
);

return (
<button
type="button"
className={styles.root()}
aria-pressed={isActive}
aria-label={ariaLabel}
onClick={handleClick}
>
<HeartIcon className={clsx(styles.icon(), iconStateClassName)} aria-hidden="true" />
</button>
);
};
23 changes: 23 additions & 0 deletions src/shared/ui/FavoriteButton/FavoriteButton.variants.ts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

variant 속성이 없는 경우 tva 의존성을 주입할 필요가 없다고 저는 개인적으로 생각해서 Styles.ts로 분리했을 것 같습니다! 제 개인적인 생각이니 참고는 해보시는 것도 좋을 것 같아요!

@YeBeenChoi YeBeenChoi Jan 20, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

의견 감사합니다! 피그마를 다시 살펴 보니 수리점 내역 화면에서도 테두리 색상이 반전된 FavoriteButton이 사용되고 있어서, default/inverse variant를 추가하면서 tv를 유지했습니다 또한 추후 카드 컴포넌트에 FavoriteButton이 추가될 경우 사이즈가 달라질 가능성도 있다고 생각해, 확장성을 고려하여 현재 구조를 유지했습니다! 필요하다면 styles로 분리하는 방향으로 수정해 보겠습니다 😀

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { tv } from 'tailwind-variants';

export const favoriteButtonVariants = tv({
slots: {
root: ['group inline-flex items-center justify-center', 'w-[44px] h-[44px]', 'transition-colors'],
icon: ['w-[33px] h-[29.26px]', 'transition-colors', '[--icon-fill-active:var(--color-green-300)]'],
},

variants: {
variant: {
default: {
icon: ['[--icon-stroke:var(--color-black)]'],
},
inverse: {
icon: ['[--icon-stroke:var(--color-white)]'],
},
},
},

defaultVariants: {
variant: 'default',
},
});
2 changes: 2 additions & 0 deletions src/shared/ui/FavoriteButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { FavoriteButton } from './FavoriteButton';
export type { FavoriteButtonProps } from './FavoriteButton';
1 change: 0 additions & 1 deletion src/shared/ui/SearchBar/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export { SearchBar } from './SearchBar';
export type { SearchBarProps } from './SearchBar';
Loading