๋์์ด๋๊ฐ ํ๋ก์ ํธ์ ํจ๊ป ํ๋ค๋๊ฑด ์ถ๋ณต์ด๋ค. ๋์์ธ์ด๋ ๊ธฐํ์ ์๊ฐ์ ์์ง ์๊ณ ๊ฐ๋ฐ์๋ง ์ง์คํ ์ ์๋ค๋ ๊ฒ ์ธ์๋ ์ป์ด๊ฐ๋ ๊ฒ์ด ๊ฝค ์๋ค. ๋์์ธ ํ์์ ๋๊ฒจ ๋ฐ์ ํผ๊ทธ๋ง ํ๋ฉด์ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฏ์ด๋ณด๋ฉด์ ๋ง์ด ๋ฐฐ์ ๋ค. ๋์์ด๋๋ค์ ์ด๋ค ๋ฐฉ์์ผ๋ก ์์
ํ๋์ง, ํผ๊ทธ๋ง์ ์ด ๊ธฐ๋ฅ์ ์ด๋ป๊ฒ ํ์ฉํ๋์ง, ํ์
์ ์ด๋ป๊ฒ ํ๋์ง.
์ด์ ํ๋ก์ ํธ์์ ๋์์ธ์ ๋งก์์ ํ ๋ ์์
์ ํจ์จ์ ์ผ๋ก ํ๋ ๋ฐฉ๋ฒ์ ์ ํ ๋ชฐ๋๋ค. ์ ๋ชฉ๊ณผ ์๋ธ ํ
์คํธ์ ๊ฐ๊ฒฉ์ ํญ์ 24ํฝ์
๋ก ํด์ผ์ง, ์ด ์ปดํฌ๋ํธ๋ ํญ์ ํ๋ฉด ๋๋น์ ์ฑ์์ง๋๋ก ํด์ผ์ง, ํ๋ ๋๋ฆ์ ๊ธฐ์ค๋ค์ ๋ ํผ์์๋ง ์๊ฐํ๊ณ ์์ผ๋๊น ๊ฐ์ด ๊ฐ๋ฐํ๋ ํ์๋ค๊ณผ ์ํต์ด ์๋ผ์ ์ผ์ ๋๋ฒ์ฉ ํ๋ ๊ฒฝ์ฐ๋ ์ฌ๋ฌ๋ฒ ์๊ฒผ๋ค. ๊ฐ ํ์ด์ง์์ ํต์ผํด์ผ ํ๋ ๋์์ธ๋ค๋ ์ฌ๋ฌ๋ช
์ด์ ์์
์ ํ๋ค๋ณด๋ ์ ๊ฒฝ์จ์ผ ํ ๊ฒ๋ ๋ง์๋ค. ์ญ์ ๋จธ๋ฆฌ๊ฐ ๋์๋ฉด ๋ชธ์ด ๊ณ ์์!!
์ฑ UI์ ์ ๋ฐ์ ์ธ ์ผ๊ด์ฑ์ด ์ค์ํจ์ ์ ๋ง ์ ์๊ณ ์๊ธฐ ๋๋ฌธ์, ๋์์ด๋๊ฐ ๊ตฌ์ํ ์คํ์ผ ๊ฐ์ด๋๋ฅผ ๊ฐ๋ฐ ๋จ๊ณ๋ก ๊ทธ๋๋ก ๋๊ณ ์ค๊ณ ์ ํ๋ค. styled-components์ ThemeProvider์ Storybook์ผ๋ก ๋์์ธ์์คํ
์ ์์ฑ๋ ์๊ฒ ๊ตฌ์ถํ ์ ์๊ฒ ๋์๋ค.
1. ThemeProvider
๋์์ด๋ ์ ์๋๋ค์ด ๋๊ฒจ์ค ์ ํ๋ ํธ์ ํ์ดํฌ์ด๋ค. ๋์์ธ์ ์ฌ์ฉ๋ ๋ชจ๋ ์์๋ค์ ํผ๊ทธ๋ง ๋ด์์ ์ง์ ๋ ์ด๋ฆ์ผ๋ก ๋ณผ ์ ์๋ค. ํ์ดํฌ๋ ๋์ผ. ๋์์ด๋๊ฐ ํฐํธ, ๊ตต๊ธฐ, ํฌ๊ธฐ๊ฐ ๋๊ฐ์ ์คํ์ผ์ด์ด๋ ์ฐ์ด๋ ์ฉ๋์ ๋ฐ๋ผ ๋ฐ๋ก ๋ถ๋ฆฌ๋ฅผ ํด์ฃผ์ด์ ์ข ๋ ํธํ๊ฒ ์ฌ์ฉํ ์ ์์๋ค.
context๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ํ๋ themeProvider๋ฅผ ํตํด ์ ์ญ์ผ๋ก theme์ ๋ถ๋ฌ์์ ์ฌ์ฉํ ์ ์๋ค. ๋ฏธ๋ฆฌ ์ธํ ํ ์๋ค์ด ์๋์์ฑ์ผ๋ก ๋ฐ๋ก ๋ฌ๋ค.
ํ์ดํฌ์ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง. ๊ธ๊ผด, ๊ตต๊ธฐ, ํฌ๊ธฐ, ์ค ๋์ด๋ฅผ ์ค์ ํด๋์๋ค. ์๋์์ฑ์ ํตํด ์์ฝ๊ฒ ํ๋ฒ์ ๋ค๊ฐ์ง ์์ฑ์ ๋ถ๋ฌ์ฌ ์ ์๋ค.
๊ทธ ์ธ์๋ ๋ฏธ๋์ด์ฟผ๋ฆฌ, ๋ชจ์๋ฆฌ ๋ฅ๊ธ๊ธฐ ๋ฑ์ ๋ถ๋ฌ์ ์ฌ์ฉํ๋ค.
theme.tsx
import { DefaultTheme } from 'styled-components';
// div ๋ด๋ถ์ svg๋ฅผ ์ฝ์
ํ์ฌ ์์น์ํค๋ ๊ฒฝ์ฐ ๋ด๋ถ svg์ width๋ฅผ
// % ๋จ์๋ก ๊ณ์ฐํ๊ธฐ ์ํ ํจ์, ์์์ ์๋๋ ๋ฒ๋ฆผ
export const calcRatio = (innerPx: number, OuterPx: number) =>
`${Math.floor((innerPx * 100) / OuterPx)}%`;
export const calcRem = (px: number) => `${px / 16}rem`;
const customMediaQuery = (maxWidth: number): string =>
`@media (max-width: ${maxWidth}px)`;
export const media = {
custom: customMediaQuery,
pc: customMediaQuery(1440),
tablet: customMediaQuery(768),
mobile: customMediaQuery(576),
};
export const theme: DefaultTheme = {
palette: {
main: {
yellow100: '#FFF6D2',
yellow200: '#FFEEA6',
yellow300: '#FFDA40',
yellow400: '#FFC52F',
},
greyScale: {
white: '#FFFFFF',
grey100: '#FAFAFC',
grey200: '#EAEAEC',
grey300: '#DBDEE1',
grey400: '#CFCFCF',
grey500: '#A6A9AD',
grey600: '#828489',
grey700: '#525354',
black: '#2E3234',
},
// ...์๋ต
},
radius: {
small: '8px',
medium: '12px',
large: '24px',
},
typo: {
fixed: {
Navbar_T_17_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
17,
)};line-height: 100%;font-weight: 800;`,
TabName_T_21_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
21,
)};line-height: 100%;font-weight: 800;`,
HomeTitle_T_24_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
24,
)};line-height: 100%;font-weight: 800;`,
HomeSubtitle_T_16_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
16,
)};line-height: 100%;font-weight: 800;`,
GraphNum_T_21_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
21,
)};line-height: 100%;font-weight: 800;`,
GraphSub_S_12_M: `font-family: 'Spoqa Han Sans Neo';font-size: ${calcRem(
12,
)};line-height: 100%;font-weight: 500;`,
EmptyText_S_16_M: `font-family: 'Spoqa Han Sans Neo';font-size: ${calcRem(
16,
)};line-height: 100%;font-weight: 500;`,
},
input: {
Title_T_24_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
24,
)};line-height: 100%;font-weight: 800;`,
TextField_T_16_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
16,
)};line-height: 100%;font-weight: 800;`,
TextField_Num_T_21_EB: `font-family: 'TmoneyRoundWind';font-size: ${calcRem(
21,
)};line-height: 100%;font-weight: 800;`,
TextMessage_S_12_M: `font-family: 'Spoqa Han Sans Neo';font-size: ${calcRem(
12,
)};line-height: 100%;font-weight: 500;`,
},
// ...์๋ต
},
};
2. Storybook
๋์์ธ์์คํ ์๋ ํ์ดํฌ์ ํ๋ ํธ ๋ฟ๋ง ์๋๋ผ ๊ทธ๋ฆฌ๋์์คํ , ๋ฒํผ, ํญ๋ฐ, ์ธํ ๋ฐ์ค ๋ฑ์ ๊ณตํต์ผ๋ก ์ฐ์ด๋ ์ปดํฌ๋ํธ๋ค๋ ์ ์๊ฐ ๋์ด์๋ค. ์ด์ ์ ์ฌ์ฉํด๋ณธ ๊ฒฝํ์ด ์๋ ์คํ ๋ฆฌ๋ถ์ ์ด๋ฒ ํ๋ก์ ํธ์๋ ๋์ ํ๊ธฐ๋ก ํ๋ค. ๊ฐ์ด๋๊ฐ ์ ๋์ด ์์ผ๋ ๋์ฑ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ ๊ฒ์ด๋ผ ๊ธฐ๋ํ๋ค.
ํผ๊ทธ๋ง์์ ํ๋์ ์ปดํฌ๋ํธ์ properties๋ฅผ ๋ค์ํ๊ฒ ์ค ์ ๊ฐ ์๋ค. ๋์์ด๋๊ฐ ์์ ํ๋ ๋ฐฉ์ ๊ทธ๋๋ก ๋ฆฌ์กํธ์ค๋ฝ๊ฒ ์ฝ๋์ ๋ฐ์ํ ์ ์๋ค. props๋ฅผ ๋ค๋ฅด๊ฒ ๋ฃ์ด์ฃผ๋ฉด์ ํ๋์ ์ปดํฌ๋ํธ์ ๋ค์ํ variants๋ฅผ ํ ์คํธํ ์ ์๊ฒ ๋์๋ค.
[React] Storybook ์ค์ ๋ฐ Github Actions ๋ฐฐํฌ ์๋ํ
์คํ ๋ฆฌ๋ถ ํ์ด์ง๋ dev ๋ธ๋์น์ push๊ฐ ์๊ณ , ์ปดํฌ๋ํธ ๋๋ ํ ๋ฆฌ์ ๋ณ๊ฒฝ์ด ์์ ๋์๋ง ์ก์ ์ด ํธ๋ฆฌ๊ฑฐ ๋๋ฉด์ ์๋์ผ๋ก ๋ฐฐํฌ๋๋๋ก ์ค์ ํ๋ค. ๊ทธ ๊ณผ์ ์ ์ ์์ ๋ชฉ์ ๊ฑธ์ด๋ ๋งํฌ์ ์ ๋ฆฌํด๋์๋ค.
[ํฐ์ผ ์๋งค ํ๋ก์ ํธ] 2. CDD, Storybook
์คํ ๋ฆฌ๋ถ์ ํตํ ์ปดํฌ๋ํธ ์ฃผ๋ ๊ฐ๋ฐ์ ๋ํ ์ด์ผ๊ธฐ๋ ์ด์ ํ๋ก์ ํธ๋ฅผ ํ๋ฉด์ ์ ๋ฆฌํด๋์๋ค. ์ญ์ ์ ์์ ๋ชฉ์ ๊ฑธ์ด๋ ๋งํฌ์์ ๋ณผ ์ ์๋ค. ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฐ์ง ์์์ ๋๋ PropTypes๋ฅผ ์ด์ฉํด ์ปดํฌ๋ํธ prop์ ๋ค์ด๊ฐ๋ ์์ฑ๋ค๊ณผ ํ์ ์ ์ง์ ํด๋์๋๋ฐ, ์ด๋ฐ ๊ฒฝํ ๋๋ถ์ ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฒ์ ๊ณต๋ถํ ๋๋ ์ต์ํ ๋๋์ ๋ฐ์ ์ ์์๋ค.