diff --git a/app/page.tsx b/app/page.tsx index 718c073..19f56fb 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,9 +1,10 @@ import Blur from "@/components/common/Blur"; +import Button from "@/components/ui/Button"; export default function Home() { return (
- +
); } diff --git a/app/tokens.css b/app/tokens.css index 02dc7fb..753c63a 100644 --- a/app/tokens.css +++ b/app/tokens.css @@ -135,169 +135,169 @@ @layer utilities { /* Font utilities */ - .text-16-400 { + .typo-16-400 { font-size: 16px; font-weight: 400; line-height: 1.5; } - .text-16-500 { + .typo-16-500 { font-size: 16px; font-weight: 500; line-height: 1.5; } - .text-16-600 { + .typo-16-600 { font-size: 16px; font-weight: 600; line-height: 1.5; } - .text-16-700 { + .typo-16-700 { font-size: 16px; font-weight: 700; line-height: 1.5; } - .text-20-400 { + .typo-20-400 { font-size: 20px; font-weight: 400; line-height: 1.5; } - .text-20-500 { + .typo-20-500 { font-size: 20px; font-weight: 500; line-height: 1.5; } - .text-20-600 { + .typo-20-600 { font-size: 20px; font-weight: 600; line-height: 1.5; } - .text-20-700 { + .typo-20-700 { font-size: 20px; font-weight: 700; line-height: 1.5; } - .text-24-400 { + .typo-24-400 { font-size: 24px; font-weight: 400; line-height: 1.5; } - .text-24-500 { + .typo-24-500 { font-size: 24px; font-weight: 500; line-height: 1.5; } - .text-24-600 { + .typo-24-600 { font-size: 24px; font-weight: 600; line-height: 1.5; } - .text-24-700 { + .typo-24-700 { font-size: 24px; font-weight: 700; line-height: 1.5; } - .text-12-400 { + .typo-12-400 { font-size: 12px; font-weight: 400; line-height: 1.5; } - .text-12-500 { + .typo-12-500 { font-size: 12px; font-weight: 500; line-height: 1.5; } - .text-12-600 { + .typo-12-600 { font-size: 12px; font-weight: 600; line-height: 1.5; } - .text-12-700 { + .typo-12-700 { font-size: 12px; font-weight: 700; line-height: 1.5; } - .text-14-400 { + .typo-14-400 { font-size: 14px; font-weight: 400; line-height: 1.5; } - .text-14-500 { + .typo-14-500 { font-size: 14px; font-weight: 500; line-height: 1.5; } - .text-14-600 { + .typo-14-600 { font-size: 14px; font-weight: 600; line-height: 1.5; } - .text-14-700 { + .typo-14-700 { font-size: 14px; font-weight: 700; line-height: 1.5; } - .text-10-400 { + .typo-10-400 { font-size: 10px; font-weight: 400; line-height: 1.5; } - .text-10-500 { + .typo-10-500 { font-size: 10px; font-weight: 500; line-height: 1.5; } - .text-10-600 { + .typo-10-600 { font-size: 10px; font-weight: 600; line-height: 1.5; } - .text-10-700 { + .typo-10-700 { font-size: 10px; font-weight: 700; line-height: 1.5; } - .text-18-400 { + .typo-18-400 { font-size: 18px; font-weight: 400; line-height: 1.5; } - .text-18-500 { + .typo-18-500 { font-size: 18px; font-weight: 500; line-height: 1.5; } - .text-18-600 { + .typo-18-600 { font-size: 18px; font-weight: 600; line-height: 1.5; } - .text-18-700 { + .typo-18-700 { font-size: 18px; font-weight: 700; line-height: 1.5; diff --git a/components/ui/Button.tsx b/components/ui/Button.tsx new file mode 100644 index 0000000..d3740d1 --- /dev/null +++ b/components/ui/Button.tsx @@ -0,0 +1,99 @@ +import React from "react"; +import { cn } from "@/lib/utils"; + +interface ButtonProps extends React.ButtonHTMLAttributes { + children: React.ReactNode; + backgroundColor?: string; + width?: string; + height?: string; + fixed?: boolean; + bottom?: number; // 하단 여백 (px) + sideGap?: number; // 좌우 여백 (px) + maxWidth?: number; // fixed일 때 최대 너비 (px) + textColor?: string; + fontSize?: string; + safeArea?: boolean; // safe-area-inset-bottom 적용 여부 + ref?: React.Ref; +} + +export default function Button({ + children, + backgroundColor = "bg-button-primary", + width = "w-full", + height = "h-12", + fixed = false, + bottom = 0, + sideGap = 16, + maxWidth = 430, + textColor = "text-button-primary-text-default", + fontSize = "typo-20-600", + safeArea = true, + disabled = false, + className, + ref, + type = "button", + ...props +}: ButtonProps) { + // disabled 상태에 따른 배경색/텍스트색 결정 + const finalBackgroundColor = disabled + ? "bg-button-background-disabled" + : backgroundColor; + const finalTextColor = disabled + ? "text-button-primary-text-disabled" + : textColor; + + // bg-button-primary일 때 border와 shadow 추가 + const isPrimaryButton = finalBackgroundColor === "bg-button-primary"; + + // fixed일 때 bottom 계산 (safeArea 적용) + const getBottomValue = () => { + if (!fixed) return undefined; + + if (safeArea) { + return `calc(${bottom}px + env(safe-area-inset-bottom))`; + } + + return `${bottom}px`; + }; + + return ( + + ); +} diff --git a/scripts/generate-tokens.js b/scripts/generate-tokens.js index c047395..3e34833 100644 --- a/scripts/generate-tokens.js +++ b/scripts/generate-tokens.js @@ -176,14 +176,14 @@ colorTokens }); const textColorUtilities = Array.from(textColorUtilitiesSet).sort().join("\n"); -// 폰트 사이즈 유틸리티 (text-{size}-{weight}) +// 폰트 사이즈 유틸리티 (typo-{size}-{weight}) const weights = ["400", "500", "600", "700"]; const fontUtilitiesSet = new Set(); fontTokens.forEach((t) => { const size = t.value; if (typeof size === "number") { weights.forEach((weight) => { - fontUtilitiesSet.add(` .text-${size}-${weight} { + fontUtilitiesSet.add(` .typo-${size}-${weight} { font-size: ${size}px; font-weight: ${weight}; line-height: 1.5;