diff --git a/src/app/preview/button/page.tsx b/src/app/preview/button/page.tsx index 84f2e95..222cba6 100644 --- a/src/app/preview/button/page.tsx +++ b/src/app/preview/button/page.tsx @@ -1,23 +1,27 @@ 'use client'; import { Button } from '@/components/ui/Button'; +import { FloatingButton } from '@/components/ui/FloatingButton'; import { + ArrowUp, Download, Heart, LogOut, MessageCircle, + Plus, Settings, Share2, Star, } from 'lucide-react'; -import React from 'react'; +import React, { useCallback, useState } from 'react'; export default function ButtonExamples() { const handleClick = () => { alert('hiii'); }; + return ( -
+
{/* Default buttons with different variants */}

기본 버튼 스타일

@@ -36,7 +40,6 @@ export default function ButtonExamples() {
- {/* Small buttons row */}

작은 크기 버튼

@@ -52,7 +55,6 @@ export default function ButtonExamples() {
- {/* Disabled states */}

비활성화 상태

@@ -71,6 +73,40 @@ export default function ButtonExamples() {
+ {/* 찜 버튼 */} +
+

찜 버튼

+ + + +
+ {/* 플로팅 버튼 섹션 */} +

플로팅 버튼

+ } className="bottom-24" /> + }> + 모임 만들기 + + } + className="right-6 top-1/2 -translate-y-1/2" // 중간위치 + /> ); } + +function LikeButton() { + const [isLiked, setIsLiked] = useState(false); + + const handleLikeClick = useCallback(() => { + setIsLiked((prev) => !prev); + }, []); + + return ( + + ); +} diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx index 53c740e..1a1c88b 100644 --- a/src/components/ui/Button.tsx +++ b/src/components/ui/Button.tsx @@ -10,7 +10,6 @@ const buttonVariants = cva( variant: { solid: [ 'bg-main', - 'typo-button1', 'text-white', 'hover:opacity-90', 'disabled:bg-disable disabled:text-disable_text', @@ -18,27 +17,24 @@ const buttonVariants = cva( default: [ 'bg-default', 'text-main', - 'typo-button1', 'hover:opacity-90', 'disabled:bg-disable disabled:text-disable_text', ], outline: [ 'border border-main', 'text-main', - 'typo-button1', 'hover:bg-default', 'disabled:border-disable disabled:text-disable_text', ], text: [ 'text-main', - 'typo-button1', 'hover:text-opacity-80', 'disabled:text-disable_text', ], }, size: { - default: 'h-[46px] w-[332px]', - sm: 'h-10 w-[120px]', + default: ['typo-button1 h-[46px] w-[332px]'], + sm: ['typo-button2 h-10 w-[120px]'], }, }, defaultVariants: { diff --git a/src/components/ui/FloatingButton.tsx b/src/components/ui/FloatingButton.tsx new file mode 100644 index 0000000..bf3230d --- /dev/null +++ b/src/components/ui/FloatingButton.tsx @@ -0,0 +1,63 @@ +import { cn } from '@/util/cn'; +import { Slot } from '@radix-ui/react-slot'; +import { type VariantProps, cva } from 'class-variance-authority'; +import * as React from 'react'; + +const floatingButtonVariants = cva( + 'fixed bottom-6 right-6 inline-flex items-center justify-center gap-2 rounded-full bg-main text-white transition-colors hover:opacity-90 focus-visible:outline-none disabled:pointer-events-none disabled:bg-disable disabled:text-disable_text [&_svg]:pointer-events-none [&_svg]:shrink-0', + { + variants: { + variant: { + icon: ['h-14 w-14', '[&_svg]:size-6'], + text: ['typo-head3', 'p-4', '[&_svg]:size-6'], + }, + }, + defaultVariants: { + variant: 'icon', + }, + }, +); + +export interface FloatingButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; + icon?: React.ReactNode; +} + +/** + * Floating Button 컴포넌트입니다.(기본 fixed 우측하단-6) + * @example + * // 아이콘만 있는 경우 + * } /> + * + * // 텍스트와 함께 사용 + * } variant="text">모임 만들기 + * + * @param {object} props + * @param {string} [props.className] - Tailwind CSS 클래스를 통한 커스텀 스타일 + * @param {'icon' | 'text'} [props.variant='icon'] - 버튼의 스타일 variant (아이콘만 있는 경우 / 텍스트가 있는 경우) + * @param {React.ReactNode} [props.icon] - 버튼에 표시될 아이콘 + * @param {boolean} [props.disabled] - 버튼 비활성화 상태 + * @param {() => void} [props.onClick] - 클릭 이벤트 핸들러 + * @param {boolean} [props.asChild=false] - true일 경우 다른 컴포넌트로 래핑 가능 + */ +const FloatingButton = React.forwardRef( + ({ className, variant, icon, children, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + {icon} + {children} + + ); + }, +); + +FloatingButton.displayName = 'FloatingButton'; + +export { FloatingButton, floatingButtonVariants };