From 6cacddcea95d753253b7e330f5439976a940fc95 Mon Sep 17 00:00:00 2001 From: polee <43488305+poiu694@users.noreply.github.com> Date: Sun, 30 Jun 2024 03:28:00 +0900 Subject: [PATCH] feat: define color token (#36) * feat: define color token * feat: typography component with font token * feat: apply typography component * chore: edit story in chip * feat: add colorscheme type in chip button * refactor: percent to em --- package-lock.json | 120 ++++++++++++++ src/app/page.tsx | 33 +++- src/components/common/button.tsx | 67 ++++---- src/components/common/chip-button.tsx | 29 ++-- src/components/common/chip.tsx | 44 +++-- src/components/common/icon.tsx | 60 +++++-- src/components/common/index.ts | 1 + src/components/common/typography.tsx | 111 +++++++++++++ src/components/search-input/index.tsx | 2 +- .../accessible-icon-button.stories.tsx | 4 +- src/stories/chip-button.stories.tsx | 1 - src/stories/chip.stories.tsx | 2 +- src/stories/icon.stories.tsx | 64 ++++++-- src/stories/typography.stories.tsx | 89 ++++++++++ src/types/color.ts | 30 +++- src/utils/cn.ts | 64 +++++++- tailwind.config.ts | 152 +++++++++++++++++- 17 files changed, 769 insertions(+), 104 deletions(-) create mode 100644 src/components/common/typography.tsx create mode 100644 src/stories/typography.stories.tsx diff --git a/package-lock.json b/package-lock.json index 35d18e44..99b4b5a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18458,6 +18458,126 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz", + "integrity": "sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz", + "integrity": "sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz", + "integrity": "sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz", + "integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz", + "integrity": "sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz", + "integrity": "sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz", + "integrity": "sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz", + "integrity": "sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } diff --git a/src/app/page.tsx b/src/app/page.tsx index 3753f071..d710a003 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,10 +1,41 @@ -import { Button, QRCode } from '@/components' +import { Button, Chip, ChipButton, QRCode, Typography } from '@/components' const Home = () => { return (
+ + Typography + + + Typography + + Typography + Typography + Typography + Typography + Typography + Typography + Typography + Typography + Typography + Typography + Typography + Typography + + ์ง„์˜ Pick + + + ๐Ÿ ํƒœ๊ทธ์„ค๋ช… + + + ๐Ÿ ํƒœ๊ทธ์„ค๋ช… + + + ๋„๋ผ๋ฐฉ์Šค + + ํ•œ์šฐ๊ฐˆ๋น„
) } diff --git a/src/components/common/button.tsx b/src/components/common/button.tsx index 6f107da9..c168d636 100644 --- a/src/components/common/button.tsx +++ b/src/components/common/button.tsx @@ -2,39 +2,38 @@ import { forwardRef, type ButtonHTMLAttributes } from 'react' import { cva } from 'class-variance-authority' import cn from '@/utils/cn' +import Typography from './typography' +import type { ColorKey } from '@/types/color' const ButtonVariants = cva<{ colorScheme: Record<'orange' | 'neutral', string> size: Record<'sm' | 'md' | 'lg', string> rounded: Record<'xl' | 'full', string> -}>( - 'flex justify-center items-center cursor-pointer text-neutral-000 text-[18px] font-semibold leading-tight', - { - variants: { - colorScheme: { - orange: 'bg-main-orange', - neutral: 'bg-neutral-500', - }, - size: { - sm: 'py-[12px]', - md: 'py-[15px]', - lg: 'py-[18px]', - }, - rounded: { - xl: 'rounded-xl', - full: 'rounded-full', - }, +}>('flex justify-center items-center cursor-pointer', { + variants: { + colorScheme: { + orange: 'bg-orange-400', + neutral: 'bg-neutral-500', }, - defaultVariants: { - colorScheme: 'orange', - size: 'md', - rounded: 'full', + size: { + sm: 'py-[12px]', + md: 'py-[15px]', + lg: 'py-[18px]', + }, + rounded: { + xl: 'rounded-xl', + full: 'rounded-full', }, }, -) + defaultVariants: { + colorScheme: 'orange', + size: 'md', + rounded: 'full', + }, +}) -const darkDisableClass = 'bg-neutral-600 text-neutral-400 cursor-not-allowed' -const lightDisableClass = 'bg-neutral-100 text-neutral-200 cursor-not-allowed' +const darkDisableClass = 'bg-neutral-600 cursor-not-allowed' +const lightDisableClass = 'bg-neutral-100 cursor-not-allowed' interface ButtonProps extends ButtonHTMLAttributes { colorScheme?: 'orange' | 'neutral' @@ -47,11 +46,13 @@ interface ButtonProps extends ButtonHTMLAttributes { const getDisabledClassName = ( disabled: boolean, disabledColor: 'dark' | 'light', -) => { +): { disabledClassName: string; disabledTextColor: ColorKey } => { if (!disabled) { - return '' + return { disabledClassName: '', disabledTextColor: 'neutral-000' } } - return disabledColor === 'dark' ? darkDisableClass : lightDisableClass + return disabledColor === 'dark' + ? { disabledClassName: darkDisableClass, disabledTextColor: 'neutral-400' } + : { disabledClassName: lightDisableClass, disabledTextColor: 'neutral-200' } } const Button = forwardRef( @@ -69,7 +70,10 @@ const Button = forwardRef( }, ref, ) => { - const disabledClassName = getDisabledClassName(disabled, disabledColor) + const { disabledClassName, disabledTextColor } = getDisabledClassName( + disabled, + disabledColor, + ) return ( ) }, diff --git a/src/components/common/chip-button.tsx b/src/components/common/chip-button.tsx index 62b0272c..97fecf96 100644 --- a/src/components/common/chip-button.tsx +++ b/src/components/common/chip-button.tsx @@ -4,21 +4,22 @@ import { cva, VariantProps } from 'class-variance-authority' import cn from '@/utils/cn' import Icon from './icon' +import Typography from './typography' +import type { ColorKey } from '@/types/color' -const ChipButtonVariants = cva( - 'rounded-[20px] flex justify-center items-center px-[10px] py-2 leading-tight tracking-[-0.02em]', - { - variants: { - colorScheme: { - neutral: 'bg-neutral-500 text-neutral-100', - orange: 'bg-main-orange text-neutral-000', - }, - }, - defaultVariants: { - colorScheme: 'neutral', +const ChipButtonVariants = cva<{ + colorScheme: Record<'neutral' | 'orange', `bg-${ColorKey}`> +}>('rounded-3xl flex justify-center items-center px-[10px] py-2', { + variants: { + colorScheme: { + neutral: 'bg-neutral-500', + orange: 'bg-orange-400', }, }, -) + defaultVariants: { + colorScheme: 'neutral', + }, +}) interface ChipButtonProps extends ButtonHTMLAttributes, @@ -42,7 +43,9 @@ const ChipButton = forwardRef( )} {...props} > - {children} + + {children} + {rightIcon && } ) diff --git a/src/components/common/chip.tsx b/src/components/common/chip.tsx index 5e47b2b0..7d147c09 100644 --- a/src/components/common/chip.tsx +++ b/src/components/common/chip.tsx @@ -1,41 +1,57 @@ import { forwardRef } from 'react' -import type { HTMLAttributes, ReactNode } from 'react' +import type { ForwardedRef, HTMLAttributes, ReactNode } from 'react' import { cva } from 'class-variance-authority' import cn from '@/utils/cn' +import Typography, { type FontKey } from './typography' const ChipVariants = cva<{ - colorScheme: Record<'neutral' | 'orange', string> + colorScheme: Record<'neutral-400' | 'neutral-500' | 'orange', string> size: Record<'sm' | 'md' | 'lg', string> -}>('rounded px-2 py-1 text-[13px] font-medium leading-tight', { +}>('rounded-full', { variants: { colorScheme: { - neutral: 'bg-neutral-600 text-neutral-300', - orange: 'bg-neutral-800 text-main-orange', + 'neutral-400': 'bg-neutral-400 text-neutral-000', + 'neutral-500': 'bg-neutral-500 text-neutral-400', + orange: 'bg-orange-400 text-neutral-000', }, size: { - sm: 'px-[6px] py-[8px]', - md: 'px-2 py-1', - lg: 'px-[10px] py-[6px]', + sm: 'px-2 py-1', + md: 'px-[10px] py-2', + lg: 'px-5 py-2', }, }, defaultVariants: { - colorScheme: 'neutral', + colorScheme: 'neutral-400', size: 'md', }, }) interface ChipProps extends HTMLAttributes { - colorScheme?: 'neutral' | 'orange' + colorScheme?: 'neutral-400' | 'neutral-500' | 'orange' size?: 'sm' | 'md' | 'lg' + fontSize?: FontKey children: ReactNode } const Chip = forwardRef( - ({ className, children, colorScheme, size, ...props }, ref) => { + ( + { + className, + children, + colorScheme, + size, + fontSize = 'h7', + color, + ...props + }, + ref, + ) => { return ( - } className={cn( ChipVariants({ colorScheme, @@ -46,7 +62,7 @@ const Chip = forwardRef( {...props} > {children} - + ) }, ) diff --git a/src/components/common/icon.tsx b/src/components/common/icon.tsx index f8ec84ae..558db664 100644 --- a/src/components/common/icon.tsx +++ b/src/components/common/icon.tsx @@ -28,12 +28,30 @@ const IconVariants = cva<{ 'neutral-600': '[&_path]:stroke-neutral-600', 'neutral-700': '[&_path]:stroke-neutral-700', 'neutral-800': '[&_path]:stroke-neutral-800', - orange: '[&_path]:stroke-main-orange', - blue: '[&_path]:stroke-main-blue', - purple: '[&_path]:stroke-main-purple', - yellow: '[&_path]:stroke-main-yellow', - pink: '[&_path]:stroke-main-pink', - green: '[&_path]:stroke-main-green', + 'orange-50': '[&_path]:stroke-orange-50', + 'orange-100': '[&_path]:stroke-orange-100', + 'orange-200': '[&_path]:stroke-orange-200', + 'orange-300': '[&_path]:stroke-orange-300', + 'orange-400': '[&_path]:stroke-orange-400', + 'orange-500': '[&_path]:stroke-orange-500', + 'orange-600': '[&_path]:stroke-orange-600', + 'orange-700': '[&_path]:stroke-orange-700', + 'orange-800': '[&_path]:stroke-orange-800', + 'purple-50': '[&_path]:stroke-purple-50', + 'purple-100': '[&_path]:stroke-purple-100', + 'purple-200': '[&_path]:stroke-purple-200', + 'purple-300': '[&_path]:stroke-purple-300', + 'purple-400': '[&_path]:stroke-purple-400', + 'purple-500': '[&_path]:stroke-purple-500', + 'purple-600': '[&_path]:stroke-purple-600', + 'purple-700': '[&_path]:stroke-purple-700', + 'purple-800': '[&_path]:stroke-purple-800', + 'yellow-100': '[&_path]:stroke-yellow-100', + 'profile-coral': '[&_path]:stroke-profile-coral', + 'profile-dark-blue': '[&_path]:stroke-profile-dark-blue', + 'profile-sky-blue': '[&_path]:stroke-profile-sky-blue', + 'profile-violet': '[&_path]:stroke-profile-violet', + 'profile-green': '[&_path]:stroke-profile-green', }, fill: { '': '', @@ -46,12 +64,30 @@ const IconVariants = cva<{ 'neutral-600': '[&_path]:fill-neutral-600', 'neutral-700': '[&_path]:fill-neutral-700', 'neutral-800': '[&_path]:fill-neutral-800', - orange: '[&_path]:fill-main-orange', - blue: '[&_path]:fill-main-blue', - purple: '[&_path]:fill-main-purple', - yellow: '[&_path]:fill-main-yellow', - pink: '[&_path]:fill-main-pink', - green: '[&_path]:fill-main-green', + 'orange-50': '[&_path]:fill-orange-50', + 'orange-100': '[&_path]:fill-orange-100', + 'orange-200': '[&_path]:fill-orange-200', + 'orange-300': '[&_path]:fill-orange-300', + 'orange-400': '[&_path]:fill-orange-400', + 'orange-500': '[&_path]:fill-orange-500', + 'orange-600': '[&_path]:fill-orange-600', + 'orange-700': '[&_path]:fill-orange-700', + 'orange-800': '[&_path]:fill-orange-800', + 'purple-50': '[&_path]:fill-purple-50', + 'purple-100': '[&_path]:fill-purple-100', + 'purple-200': '[&_path]:fill-purple-200', + 'purple-300': '[&_path]:fill-purple-300', + 'purple-400': '[&_path]:fill-purple-400', + 'purple-500': '[&_path]:fill-purple-500', + 'purple-600': '[&_path]:fill-purple-600', + 'purple-700': '[&_path]:fill-purple-700', + 'purple-800': '[&_path]:fill-purple-800', + 'yellow-100': '[&_path]:fill-yellow-100', + 'profile-coral': '[&_path]:fill-profile-coral', + 'profile-dark-blue': '[&_path]:fill-profile-dark-blue', + 'profile-sky-blue': '[&_path]:fill-profile-sky-blue', + 'profile-violet': '[&_path]:fill-profile-violet', + 'profile-green': '[&_path]:fill-profile-green', }, }, defaultVariants: { diff --git a/src/components/common/index.ts b/src/components/common/index.ts index 8d32877d..d0ccaf88 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -3,4 +3,5 @@ export { default as ChipButton } from './chip-button' export { default as Chip } from './chip' export { default as Icon } from './icon' export { default as QRCode } from './qr-code' +export { default as Typography } from './typography' export { default as VisuallyHidden } from './visually-hidden' diff --git a/src/components/common/typography.tsx b/src/components/common/typography.tsx new file mode 100644 index 00000000..8e833e72 --- /dev/null +++ b/src/components/common/typography.tsx @@ -0,0 +1,111 @@ +import { forwardRef } from 'react' +import type { ElementType, HTMLAttributes } from 'react' +import { cva } from 'class-variance-authority' + +import type { ColorKey } from '@/types/color' +import cn from '@/utils/cn' + +export type FontKey = + | 'h0' + | 'h1' + | 'h2' + | 'h3' + | 'h4' + | 'h5' + | 'h5-2' + | 'h6' + | 'h7' + | 'body0' + | 'body1' + | 'body2' + | 'body3' + | 'body4' + +export const TypographyVariants = cva<{ + size: Record + color: Record +}>('', { + variants: { + size: { + h0: 'text-h0', + h1: 'text-h1', + h2: 'text-h2', + h3: 'text-h3', + h4: 'text-h4', + h5: 'text-h5', + 'h5-2': 'text-h5-2', + h6: 'text-h6', + h7: 'text-h7', + body0: 'text-body0', + body1: 'text-body1', + body2: 'text-body2', + body3: 'text-body3', + body4: 'text-body4', + }, + color: { + 'neutral-000': 'text-neutral-000', + 'neutral-100': 'text-neutral-100', + 'neutral-200': 'text-neutral-200', + 'neutral-300': 'text-neutral-300', + 'neutral-400': 'text-neutral-400', + 'neutral-500': 'text-neutral-500', + 'neutral-600': 'text-neutral-600', + 'neutral-700': 'text-neutral-700', + 'neutral-800': 'text-neutral-800', + 'orange-50': 'text-orange-50', + 'orange-100': 'text-orange-100', + 'orange-200': 'text-orange-200', + 'orange-300': 'text-orange-300', + 'orange-400': 'text-orange-400', + 'orange-500': 'text-orange-500', + 'orange-600': 'text-orange-600', + 'orange-700': 'text-orange-700', + 'orange-800': 'text-orange-800', + 'purple-50': 'text-purple-50', + 'purple-100': 'text-purple-100', + 'purple-200': 'text-purple-200', + 'purple-300': 'text-purple-300', + 'purple-400': 'text-purple-400', + 'purple-500': 'text-purple-500', + 'purple-600': 'text-purple-600', + 'purple-700': 'text-purple-700', + 'purple-800': 'text-purple-800', + 'yellow-100': 'text-yellow-100', + 'profile-coral': 'text-profile-coral', + 'profile-dark-blue': 'text-profile-dark-blue', + 'profile-sky-blue': 'text-profile-sky-blue', + 'profile-violet': 'text-profile-violet', + 'profile-green': 'text-profile-green', + }, + }, + defaultVariants: { + size: 'h4', + color: 'neutral-000', + }, +}) + +interface TypographyProps extends HTMLAttributes { + size: FontKey + color?: ColorKey + as?: ElementType +} + +const Typography = forwardRef( + ({ size, className, children, color, as, ...props }, ref) => { + const Component = as || 'div' + + return ( + + {children} + + ) + }, +) + +Typography.displayName = 'typography' + +export default Typography diff --git a/src/components/search-input/index.tsx b/src/components/search-input/index.tsx index 6431c716..338bc838 100644 --- a/src/components/search-input/index.tsx +++ b/src/components/search-input/index.tsx @@ -9,7 +9,7 @@ const SearchInputVariants = cva<{ variant: Record<'outlined' | 'filled', string> size: Record<'sm' | 'md' | 'lg', string> }>( - `w-full leading-none caret-main-orange rounded-md placeholder:text-neutral-400`, + `w-full leading-none caret-orange-400 rounded-md placeholder:text-neutral-400`, { variants: { variant: { diff --git a/src/stories/accessible-icon-button.stories.tsx b/src/stories/accessible-icon-button.stories.tsx index c0420e7d..3391d872 100644 --- a/src/stories/accessible-icon-button.stories.tsx +++ b/src/stories/accessible-icon-button.stories.tsx @@ -24,8 +24,8 @@ export const Default: Story = { args: { icon: { type: 'infoCircle', - fill: 'blue', - stroke: 'yellow', + fill: 'orange-400', + stroke: 'yellow-100', }, label: 'Heart Icon', }, diff --git a/src/stories/chip-button.stories.tsx b/src/stories/chip-button.stories.tsx index fb36ee9a..8cf7da0b 100644 --- a/src/stories/chip-button.stories.tsx +++ b/src/stories/chip-button.stories.tsx @@ -47,7 +47,6 @@ export const WithIcon: Story = { isActive: false, rightIcon: { type: 'infoCircle', - fill: 'blue', stroke: 'neutral-500', size: 'md', }, diff --git a/src/stories/chip.stories.tsx b/src/stories/chip.stories.tsx index 79ee4853..2e4f10fb 100644 --- a/src/stories/chip.stories.tsx +++ b/src/stories/chip.stories.tsx @@ -21,7 +21,7 @@ type Story = StoryObj export const Default: Story = { args: { - colorScheme: 'neutral', + colorScheme: 'neutral-400', children: '#ํ˜ผ๋ฐฅ', }, } diff --git a/src/stories/icon.stories.tsx b/src/stories/icon.stories.tsx index 26b144c4..b44bc8b5 100644 --- a/src/stories/icon.stories.tsx +++ b/src/stories/icon.stories.tsx @@ -23,12 +23,30 @@ const meta: Meta = { 'neutral-600', 'neutral-700', 'neutral-800', - 'orange', - 'blue', - 'purple', - 'yellow', - 'pink', - 'green', + 'orange-50', + 'orange-100', + 'orange-200', + 'orange-300', + 'orange-400', + 'orange-500', + 'orange-600', + 'orange-700', + 'orange-800', + 'purple-50', + 'purple-100', + 'purple-200', + 'purple-300', + 'purple-400', + 'purple-500', + 'purple-600', + 'purple-700', + 'purple-800', + 'yellow-100', + 'profile-coral', + 'profile-dark-blue', + 'profile-sky-blue', + 'profile-violet', + 'profile-green', ], }, fill: { @@ -43,12 +61,30 @@ const meta: Meta = { 'neutral-600', 'neutral-700', 'neutral-800', - 'orange', - 'blue', - 'purple', - 'yellow', - 'pink', - 'green', + 'orange-50', + 'orange-100', + 'orange-200', + 'orange-300', + 'orange-400', + 'orange-500', + 'orange-600', + 'orange-700', + 'orange-800', + 'purple-50', + 'purple-100', + 'purple-200', + 'purple-300', + 'purple-400', + 'purple-500', + 'purple-600', + 'purple-700', + 'purple-800', + 'yellow-100', + 'profile-coral', + 'profile-dark-blue', + 'profile-sky-blue', + 'profile-violet', + 'profile-green', ], }, size: { @@ -65,7 +101,7 @@ export const Default: Story = { args: { type: 'infoCircle', stroke: 'neutral-000', - fill: 'orange', + fill: 'orange-400', size: 'lg', }, } @@ -74,7 +110,7 @@ export const LargeIcon: Story = { args: { type: 'infoCircle', stroke: 'neutral-000', - fill: 'purple', + fill: 'purple-400', size: 'lg', }, } diff --git a/src/stories/typography.stories.tsx b/src/stories/typography.stories.tsx new file mode 100644 index 00000000..88c3b21d --- /dev/null +++ b/src/stories/typography.stories.tsx @@ -0,0 +1,89 @@ +import { Meta, StoryObj } from '@storybook/react' + +import { Typography } from '@/components' + +const meta: Meta = { + title: 'Components/Typography', + component: Typography, + argTypes: { + size: { + control: 'select', + options: [ + 'h0', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h5-2', + 'h6', + 'h7', + 'body0', + 'body1', + 'body2', + 'body3', + 'body4', + ], + }, + color: { + control: 'select', + options: [ + 'neutral-000', + 'neutral-100', + 'neutral-200', + 'neutral-300', + 'neutral-400', + 'neutral-500', + 'neutral-600', + 'neutral-700', + 'neutral-800', + 'orange-50', + 'orange-100', + 'orange-200', + 'orange-300', + 'orange-400', + 'orange-500', + 'orange-600', + 'orange-700', + 'orange-800', + 'purple-50', + 'purple-100', + 'purple-200', + 'purple-300', + 'purple-400', + 'purple-500', + 'purple-600', + 'purple-700', + 'purple-800', + 'yellow-100', + 'profile-coral', + 'profile-dark-blue', + 'profile-sky-blue', + 'profile-violet', + 'profile-green', + ], + }, + children: { + control: 'text', + }, + }, +} + +export default meta +type Story = StoryObj + +export const Default: Story = { + args: { + size: 'h4', + color: 'neutral-000', + children: 'Default Typography', + }, +} + +export const CustomSizeColor: Story = { + args: { + size: 'h1', + color: 'orange-500', + children: 'Custom Size and Color Typography', + }, +} diff --git a/src/types/color.ts b/src/types/color.ts index 0ebe207c..95fd2bd3 100644 --- a/src/types/color.ts +++ b/src/types/color.ts @@ -8,9 +8,27 @@ export type ColorKey = | 'neutral-600' | 'neutral-700' | 'neutral-800' - | 'orange' - | 'blue' - | 'purple' - | 'yellow' - | 'pink' - | 'green' + | 'orange-50' + | 'orange-100' + | 'orange-200' + | 'orange-300' + | 'orange-400' + | 'orange-500' + | 'orange-600' + | 'orange-700' + | 'orange-800' + | 'purple-50' + | 'purple-100' + | 'purple-200' + | 'purple-300' + | 'purple-400' + | 'purple-500' + | 'purple-600' + | 'purple-700' + | 'purple-800' + | 'yellow-100' + | 'profile-coral' + | 'profile-dark-blue' + | 'profile-sky-blue' + | 'profile-violet' + | 'profile-green' diff --git a/src/utils/cn.ts b/src/utils/cn.ts index 63918477..b5cc011a 100644 --- a/src/utils/cn.ts +++ b/src/utils/cn.ts @@ -1,8 +1,66 @@ import { clsx, type ClassValue } from 'clsx' -import { twMerge } from 'tailwind-merge' +import { extendTailwindMerge } from 'tailwind-merge' -const cn = (...inputs: ClassValue[]) => { - return twMerge(clsx(inputs)) +export const extendTwMerge = extendTailwindMerge({ + extend: { + classGroups: { + 'font-size': [ + 'text-h0', + 'text-h1', + 'text-h2', + 'text-h3', + 'text-h4', + 'text-h5', + 'text-h5-2', + 'text-h6', + 'text-h7', + 'text-body0', + 'text-body1', + 'text-body2', + 'text-body3', + 'text-body4', + ], + 'text-color': [ + 'text-neutral-000', + 'text-neutral-100', + 'text-neutral-200', + 'text-neutral-300', + 'text-neutral-400', + 'text-neutral-500', + 'text-neutral-600', + 'text-neutral-700', + 'text-neutral-800', + 'text-orange-50', + 'text-orange-100', + 'text-orange-200', + 'text-orange-300', + 'text-orange-400', + 'text-orange-500', + 'text-orange-600', + 'text-orange-700', + 'text-orange-800', + 'text-purple-50', + 'text-purple-100', + 'text-purple-200', + 'text-purple-300', + 'text-purple-400', + 'text-purple-500', + 'text-purple-600', + 'text-purple-700', + 'text-purple-800', + 'text-yellow-100', + 'text-profile-coral', + 'text-profile-dark-blue', + 'text-profile-sky-blue', + 'text-profile-violet', + 'text-profile-green', + ], + }, + }, +}) + +const cn = (...inputs: ClassValue[]): string => { + return extendTwMerge(clsx(inputs)) } export default cn diff --git a/tailwind.config.ts b/tailwind.config.ts index 5092e02e..444f1915 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -9,13 +9,127 @@ const config: Config = { ], theme: { extend: { + fontSize: { + h0: [ + '32px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + h1: [ + '28px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + h2: [ + '24px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + h3: [ + '20px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + h4: [ + '18px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + h5: [ + '16px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + 'h5-2': [ + '15px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + h6: [ + '14px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + h7: [ + '13px', + { + lineHeight: '1.25', + letterSpacing: '-0.005em', + fontWeight: 600, + }, + ], + body0: [ + '18px', + { + lineHeight: '1.25', + letterSpacing: '-0.02em', + fontWeight: 400, + }, + ], + body1: [ + '16px', + { + lineHeight: '1.25', + letterSpacing: '-0.02em', + fontWeight: 400, + }, + ], + body2: [ + '15px', + { + lineHeight: '1.25', + letterSpacing: '-0.02em', + fontWeight: 400, + }, + ], + body3: [ + '14px', + { + lineHeight: '1.25', + letterSpacing: '-0.02em', + fontWeight: 400, + }, + ], + body4: [ + '13px', + { + lineHeight: '1.25', + letterSpacing: '-0.02em', + fontWeight: 400, + }, + ], + }, fontFamily: { pretendard: ['var(--font-pretendard)'], }, colors: { neutral: { '000': '#FFFFFF', - '100': '#ADB1BA', + '100': '#EAEBEE', '200': '#ADB1BA', '300': '#868B94', '400': '#6D717A', @@ -24,12 +138,36 @@ const config: Config = { '700': '#212124', '800': '#17171A', }, - main: { - orange: '#E5684C', - blue: '#3177FF', - purple: '#5D5FEF', - yellow: '#FFEA2F', - pink: '#EFA5AE', + orange: { + '50': '#FDF5F3', + '100': '#FCE8E4', + '200': '#FBD5CD', + '300': '#F7B8AA', + '400': '#E5684C', + '500': '#D24E30', + '600': '#B03E25', + '700': '#B32F1B', + '800': '#8F281D', + }, + purple: { + '50': '#EFEFFD', + '100': '#E7E7FD', + '200': '#CDCDFA', + '300': '#5D5FEF', + '400': '#5456D7', + '500': '#4A4CBF', + '600': '#4647B3', + '700': '#38398F', + '800': '#2A2B6C', + }, + yellow: { + '100': '#FFDE59', + }, + profile: { + coral: '#E5684C', + 'dark-blue': '#5456D7', + 'sky-blue': '#0091FF', + violet: '#A463FF', green: '#00B57C', }, },