Skip to content

Commit

Permalink
[ORT-1] feat: add design tokens & add Button (#1)
Browse files Browse the repository at this point in the history
* feat: add design tokens

* feat: add `Button`

* feat: add `rgba` util

* refactor: modify return type of `getRGBFromHex`

* style: update comments of `getMediaQuery`

* refactor: import types properly

* fix: add font weight range & remove default button style
  • Loading branch information
aube-dev authored Aug 16, 2024
1 parent e941056 commit 5eebbd2
Show file tree
Hide file tree
Showing 12 changed files with 449 additions and 2 deletions.
9 changes: 9 additions & 0 deletions app/components/Test/Test.css.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { style } from '@vanilla-extract/css';
import { textStyle } from '@/styles/text.css';
import { themeVars } from '@/styles/theme.css';

export const container = style({
width: 200,
Expand All @@ -8,3 +10,10 @@ export const container = style({
alignItems: 'center',
backgroundColor: '#f2f2f2',
});

export const labelText = style([
textStyle.body1R,
{
color: themeVars.color.primary.normal.hex,
},
]);
6 changes: 5 additions & 1 deletion app/components/Test/Test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import * as styles from './Test.css';

const Test = () => <div className={styles.container}>Test</div>;
const Test = () => (
<div className={styles.container}>
<span className={styles.labelText}>Test</span>
</div>
);

export default Test;
82 changes: 82 additions & 0 deletions app/components/common/Button/Button.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { style, styleVariants } from '@vanilla-extract/css';
import { Breakpoint } from '@/constants/style';
import { themeVars } from '@/styles/theme.css';
import { getMediaQuery, rgba } from '@/utils/style';

export const buttonBase = style({
cursor: 'pointer',
appearance: 'none',
WebkitAppearance: 'none',
':disabled': {
cursor: 'not-allowed',
},
});

export const buttonStyleByVariant = styleVariants({
primary: {
backgroundColor: themeVars.color.primary.normal.hex,
color: themeVars.color.grayscale.white.hex,
border: 0,
':hover': {
backgroundColor: themeVars.color.primary.dark.hex,
},
':active': {
backgroundColor: themeVars.color.primary.darker.hex,
},
':disabled': {
backgroundColor: themeVars.color.grayscale.gray2.hex,
color: themeVars.color.grayscale.gray4.hex,
},
},
secondary: {
color: themeVars.color.primary.normal.hex,
borderWidth: '1px',
borderStyle: 'solid',
borderColor: themeVars.color.primary.normal.hex,
backgroundColor: 'transparent',
':hover': {
backgroundColor: rgba(themeVars.color.primary.normal.rgb, 0.1),
},
':active': {
backgroundColor: rgba(themeVars.color.primary.normal.rgb, 0.2),
},
':disabled': {
backgroundColor: 'transparent',
borderColor: themeVars.color.grayscale.gray3.hex,
color: themeVars.color.grayscale.gray4.hex,
},
},
});

export const buttonStyleBySize = styleVariants({
small: {
padding: '6px 12px',
borderRadius: '12px',
'@media': {
[getMediaQuery([Breakpoint.MOBILE1, Breakpoint.MOBILE2])]: {
padding: '6px 12px',
borderRadius: '10px',
},
},
},
medium: {
padding: '12px 28px',
borderRadius: '12px',
'@media': {
[getMediaQuery([Breakpoint.MOBILE1, Breakpoint.MOBILE2])]: {
padding: '10px 24px',
borderRadius: '10px',
},
},
},
large: {
padding: '12px 32px',
borderRadius: '12px',
'@media': {
[getMediaQuery([Breakpoint.MOBILE1, Breakpoint.MOBILE2])]: {
padding: '12px 32px',
borderRadius: '12px',
},
},
},
});
22 changes: 22 additions & 0 deletions app/components/common/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';

import Button from './Button';

const meta: Meta<typeof Button> = {
component: Button,
};

export default meta;

type Story = StoryObj<typeof Button>;

export const Main: Story = {
args: {
variant: 'primary',
size: 'medium',
children: '버튼 텍스트',
disabled: false,
onClick: fn(),
},
};
35 changes: 35 additions & 0 deletions app/components/common/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { type ButtonHTMLAttributes, type DetailedHTMLProps } from 'react';
import * as styles from './Button.css';
import { textStyle } from '@/styles/text.css';

interface ButtonProps
extends DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
> {
variant: 'primary' | 'secondary';
size: 'small' | 'medium' | 'large';
}

const textStyleBySize = {
small: textStyle.body1R,
medium: textStyle.body1SB,
large: textStyle.headline2B,
};

const Button = ({
variant,
size,
className,
children,
...buttonProps
}: ButtonProps) => (
<button
{...buttonProps}
className={`${styles.buttonBase} ${styles.buttonStyleByVariant[variant]} ${styles.buttonStyleBySize[size]} ${textStyleBySize[size]} ${className}`}
>
{children}
</button>
);

export default Button;
3 changes: 3 additions & 0 deletions app/components/common/Button/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Button from './Button';

export default Button;
8 changes: 8 additions & 0 deletions app/constants/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const Breakpoint = {
PC2: [1504, Infinity],
PC1: [1140, 1503],
TABLET2: [832, 1139],
TABLET1: [728, 831],
MOBILE2: [580, 727],
MOBILE1: [0, 579],
} as const;
6 changes: 6 additions & 0 deletions app/root.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import SUITVariable from '@/assets/SUIT-Variable.woff2';

globalFontFace('SUIT-Variable', {
src: `url(${SUITVariable}) format('woff2')`,
/** @link https://stackoverflow.com/questions/77467442/font-weight-too-bold-on-mobile */
fontWeight: '100 900',
});

globalStyle('*, *::before, *::after', {
Expand All @@ -12,6 +14,10 @@ globalStyle('*, *::before, *::after', {
fontFamily: 'SUIT-Variable',
});

globalStyle('html', {
fontSize: '62.5%',
});

globalStyle('body', {
margin: 0,
});
Expand Down
5 changes: 4 additions & 1 deletion app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import {
Scripts,
ScrollRestoration,
} from '@remix-run/react';
import { type ReactNode } from 'react';

import './root.css';
import '@/styles/theme.css';

export const Layout = ({ children }: { children: React.ReactNode }) => (
export const Layout = ({ children }: { children: ReactNode }) => (
<html lang="ko">
<head>
<meta charSet="utf-8" />
Expand Down
174 changes: 174 additions & 0 deletions app/styles/text.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { type ComplexStyleRule, styleVariants } from '@vanilla-extract/css';
import { Breakpoint } from '@/constants/style';
import { getMediaQuery } from '@/utils/style';

const FontWeight = {
HEAVY: 900,
EXTRA_BOLD: 800,
BOLD: 700,
SEMI_BOLD: 600,
MEDIUM: 500,
REGULAR: 400,
LIGHT: 300,
EXTRA_LIGHT: 200,
THIN: 100,
} as const;

interface TextStyleInfo {
[styleName: string]: {
[device in 'pc' | 'mobile']: {
/** px 단위 */
fontSize: number;
/** px 단위 */
lineHeight: number;
fontWeight: number;
};
};
}

const textStyleInfo = {
headline1B: {
pc: {
fontSize: 32,
lineHeight: 40,
fontWeight: FontWeight.BOLD,
},
mobile: {
fontSize: 26,
lineHeight: 32,
fontWeight: FontWeight.BOLD,
},
},
headline2B: {
pc: {
fontSize: 24,
lineHeight: 30,
fontWeight: FontWeight.BOLD,
},
mobile: {
fontSize: 20,
lineHeight: 25,
fontWeight: FontWeight.BOLD,
},
},
subtitle1B: {
pc: {
fontSize: 20,
lineHeight: 25,
fontWeight: FontWeight.BOLD,
},
mobile: {
fontSize: 16,
lineHeight: 20,
fontWeight: FontWeight.BOLD,
},
},
subtitle2B: {
pc: {
fontSize: 16,
lineHeight: 20,
fontWeight: FontWeight.BOLD,
},
mobile: {
fontSize: 14,
lineHeight: 17,
fontWeight: FontWeight.BOLD,
},
},
subtitle2SB: {
pc: {
fontSize: 16,
lineHeight: 20,
fontWeight: FontWeight.SEMI_BOLD,
},
mobile: {
fontSize: 14,
lineHeight: 17,
fontWeight: FontWeight.SEMI_BOLD,
},
},
body1SB: {
pc: {
fontSize: 14,
lineHeight: 17,
fontWeight: FontWeight.SEMI_BOLD,
},
mobile: {
fontSize: 12,
lineHeight: 15,
fontWeight: FontWeight.SEMI_BOLD,
},
},
body1R: {
pc: {
fontSize: 14,
lineHeight: 17,
fontWeight: FontWeight.REGULAR,
},
mobile: {
fontSize: 12,
lineHeight: 15,
fontWeight: FontWeight.REGULAR,
},
},
body2SB: {
pc: {
fontSize: 12,
lineHeight: 15,
fontWeight: FontWeight.SEMI_BOLD,
},
mobile: {
fontSize: 10,
lineHeight: 12,
fontWeight: FontWeight.SEMI_BOLD,
},
},
body2R: {
pc: {
fontSize: 12,
lineHeight: 15,
fontWeight: FontWeight.REGULAR,
},
mobile: {
fontSize: 10,
lineHeight: 12,
fontWeight: FontWeight.REGULAR,
},
},
} as const satisfies TextStyleInfo;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getTypedKeysFromObject = <T extends Record<string, any>>(
object: T,
): (keyof T)[] => Object.keys(object);

const getTextStyleFromInfo = <
T extends (typeof textStyleInfo)[keyof typeof textStyleInfo],
>(
info: T,
): ComplexStyleRule => ({
fontSize: `${info.pc.fontSize / 10}rem`,
lineHeight: `${info.pc.lineHeight / 10}rem`,
fontWeight: info.pc.fontWeight,
'@media': {
[getMediaQuery([Breakpoint.MOBILE1, Breakpoint.MOBILE2])]: {
fontSize: `${info.mobile.fontSize / 10}rem`,
lineHeight: `${info.mobile.lineHeight / 10}rem`,
fontWeight: info.mobile.fontWeight,
},
},
});

export const textStyle = styleVariants(
getTypedKeysFromObject(textStyleInfo).reduce<{
[key in keyof typeof textStyleInfo]: ComplexStyleRule;
}>(
(prev, styleName) => ({
...prev,
[styleName]: getTextStyleFromInfo(textStyleInfo[styleName]),
}),
{} as {
[key in keyof typeof textStyleInfo]: ComplexStyleRule;
},
),
);
Loading

0 comments on commit 5eebbd2

Please sign in to comment.