๐Ÿ’ป์›น(Web)/React

[React]Themes๋ฅผ ์ด์šฉํ•œ ์ผ๊ด€์„ฑ ์žˆ๋Š” ์Šคํƒ€์ผ ๊ด€๋ฆฌ

stonesy 2023. 6. 17. 18:54
728x90

์ด๋ฒˆ ์บก์Šคํ†ค์„ ํ•˜๋ฉด์„œ ์ผ๊ด€์„ฑ ์žˆ๋Š” ์Šคํƒ€์ผ ๊ด€๋ฆฌ์˜ ํ•„์š”์„ฑ์„ ๊นจ๋‹ฌ์•˜๋‹ค. ์ด๋•Œ, ์˜ˆ์ „์— ๋ฐฐ์› ๋˜ Themes๋ฅผ ์ ์šฉํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ณต์Šตํ• ๊ฒธ ์ •๋ฆฌํ•ด๋ณด์•˜๋‹ค. โœจ

 

๐Ÿ”ŽThemes๋ฅผ React ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

styled-components๋ฅผ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค. ์„ค์น˜ํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŒŒ์ผ์„ ์ž‘์„ฑํ•œ๋‹ค. 

1. theme ํŒŒ์ผ ์ž‘์„ฑํ•˜๊ธฐ

theme ํŒŒ์ผ์— ์‚ฌ์šฉํ•  ์Šคํƒ€์ผ์„ ์ž‘์„ฑํ•œ๋‹ค.

import { DefaultTheme } from "styled-components";

export const theme: DefaultTheme={
    bgColor: "#EFEFEF",
    subBgColor: "#FFFFFF",
    textColor: "#2f3542",
    primaryColor: "#22a6b3",
    secondaryColor: "#f0932b",
    successColor: "#192a56",
    infoColor: "#0097e6",
    dangerColor: "#c23616",
};

์ด๋•Œ, typescript๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

styled.d.ts ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  type์„ ์ง€์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

import "styled-components";

declare module 'styled-components'{
    export interface DefaultTheme{
        bgColor: string,
        subBgColor: string,
        textColor: string,
        primaryColor: string,
        secondaryColor: string,
        successColor: string,
        infoColor: string,
        dangerColor: string,
    }
}

2. ThemeProvider๋กœ theme ์ ์šฉํ•˜๊ธฐ

import React from 'react';
import ReactDOM from 'react-dom/client';
import router from "./Router";
import { RouterProvider } from 'react-router-dom';
import { createGlobalStyle, ThemeProvider } from 'styled-components';
import { theme } from './theme';

const GlobalStyle = createGlobalStyle`
  /* http://meyerweb.com/eric/tools/css/reset/ 
    v2.0 | 20110126
    License: none (public domain)
  */

  html, body, div, span, applet, object, iframe,
  h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  a, abbr, acronym, address, big, cite, code,
  del, dfn, em, img, ins, kbd, q, s, samp,
  small, strike, strong, sub, sup, tt, var,
  b, u, i, center,
  dl, dt, dd, ol, ul, li,
  fieldset, form, label, legend,
  table, caption, tbody, tfoot, thead, tr, th, td,
  article, aside, canvas, details, embed, 
  figure, figcaption, footer, header, hgroup, 
  menu, nav, output, ruby, section, summary,
  time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
  }
  /* HTML5 display-role reset for older browsers */
  article, aside, details, figcaption, figure, 
  footer, header, hgroup, menu, nav, section {
    display: block;
  }
  *{
    box-sizing: border-box;
  }
  body {
    line-height: 1;
  }
  ol, ul {
    list-style: none;
  }
  blockquote, q {
    quotes: none;
  }
  blockquote:before, blockquote:after,
  q:before, q:after {
    content: '';
    content: none;
  }
  table {
    border-collapse: collapse;
    border-spacing: 0;
  }
`;

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <RouterProvider router={router} />
    </ThemeProvider>
  </React.StrictMode>
);

3. theme ์‚ฌ์šฉํ•˜๊ธฐ

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  color: ${(props) => props.theme.bgColor}

 

*์กฐ๊ฑด์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

const StarParent = styled.p<StarParentProps>`
  width: 200%;
  height: 100%;

  position: absolute;
  top: 0;

  display: flex;
  align-items: center;
  justify-content: center;

  cursor: pointer;

  font-size: ${({ fontSize }) => `${fontSize}rem`};
  color: ${({ active, theme }: StarParentProps & { theme: DefaultTheme }) =>
    active ? theme.secondaryColor : 'lightgrey'};
`;

 

728x90