cupicks / cupicks-fe

이미지만 보고 만드는 카페 레시피 제작 및 공유 서비스
3 stars 1 forks source link

Update : styled-component 테마 적용(feat. REM) #182

Closed dusunax closed 2 years ago

dusunax commented 2 years ago

styled-component 테마 적용(feat. REM 적용)

+결론(10월 3일 추가)

  1. 적용 내용
  2. px과 rem 간단한 소개
  3. 프로젝트 적용 사례

결론

작업 마무리 - 10월 3일


적용 내용

페이지

관련 내용

출처


프로젝트에 Styled Component 테마를 적용하려고 합니다. 테마를 적용하기 앞서서 REM과 EM의 개념을 정리하고, 이를 어떻게 웹 상에서 사용할 수 있는 지 방법을 정리해보려 합니다.


REM과 EM

사용자의 모든 브라우저에는 루트 글꼴 크기 설정(root font size)이 있습니다. root font size를 적용하는 것은 시각 장애가 있는 사용자에게 매우 중요합니다.

html의 root 폰트 사이즈를 변경하고, 상대적인 사이즈를 사용하면 확대/축소 뿐만 아니라 루트 글꼴 크기 변경에도 유연하게 반응할 수 있습니다.

픽셀이란?

픽셀을 상대적 크기로 변환하기


REM

Font size of the root element.

EM

Font size of the parent, in the case of typographical properties like [font-size](<https://developer.mozilla.org/en-US/docs/Web/CSS/font-size>) and font size of the element itself, in the case of other properties like [width](<https://developer.mozilla.org/en-US/docs/Web/CSS/width>)

종류 영어 내용
REM root em unit 루트 글꼴 크기의 배수
EM em unit 글꼴 크기의 배수
px pixel 고정된 절대값

브레이크 포인트

dusunax commented 2 years ago

App, Main.jsx 정리

Main : react-route-dom

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

import { BrowserRouter } from "react-router-dom";

ReactDOM.createRoot(document.getElementById("root")).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
);

App : tracker, Provider(+GlobalStyle)

import RouteChangeTracker from "./shared/RouteChangeTracker";

import { ThemeProvider } from "styled-components";

import * as theme from "./styles/theme.js";
import GlobalStyle from "./styles/GlobalStyle";
import "./util/windowInnerHeightSet";

const App = () => {
  RouteChangeTracker();

  return (
    <ThemeProvider theme={theme}>
      <Layout />
      <GlobalStyle />
    </ThemeProvider>
  );
};

export default App;

styles/theme.js

기존 root에서 사용하던 코드를 theme.js에 정리할 예정입니다.

const input = { borderBottom: { base: "2px solid #cdcdcd", active: "2px solid #9e9e9e", }, fontSize: { base: "17px", }, padding: { base: "14px 0 11px", }, fontColor: { base: "#cdcdcd", }, };

const fonts = { size: { sm: "1rem", base: "1.6rem", lg: "2rem", xl: "2.5rem", title: "6rem", }, weight: { light: 100, normal: 400, bold: 700, }, color: { dark: "#393939", middle: "#9e9e9e", light: "#cdcdcd", alert: "#E64A3A", }, };

## Reset.css 적용하기

import { createGlobalStyle } from "styled-components"; import reset from "./customReset.css";

const GlobalStyle = createGlobalStyle` ${reset}; ...


## theme 적용하기
```jsx
import { createGlobalStyle, css } from "styled-components";
import reset from "./customReset.css";
import animations from "./animations.css";

const GlobalStyle = createGlobalStyle`
  ${reset};
  ${animations};

  ${({ theme }) => {
    return css`
      body {
        font-size: ${theme.fonts.size.base};
      }
    `;
  }}
`;

export default GlobalStyle;
dusunax commented 2 years ago

컴포넌트 단에서 GlobalStyle Theme 사용하기

dusunax commented 2 years ago

Custom Styled Component로 변환

로그인 페이지부터 진행!✍

dusunax commented 2 years ago

회원가입 페이지 진행✍

dusunax commented 2 years ago

비밀번호 찾기 페이지 완료

원석님 onSubmit관련 코드 백업: 안 쓰는 코드인데 너무 길어서 지웠습니다.

const onSubmit = async (data) => {
  console.log(data);
  // try {
  //   const res = await api(contentType).get(
  //     `/auth/send-password?email=${getValues("email")}`,
  //   );
  //   console.log(res);
  //   // alert(res.data.message);
  //   navigate("/sign-in");
  // } catch (err) {
  //   // console.log(err);
  //   // alert(err.response.data.message);
  //   setError("emailError", { message: err.response.data.message });
  //   setEmailError(true);
  //   setTimeout(() => {
  //     setEmailError(false);
  //   }, 1000);
  // }
};

// setCheck(true);
// setTimeout(() => {
//   setCheck(false);
// }, 1000);
dusunax commented 2 years ago

네비게이션, 헤더, 푸터 작업 => 완료!

const CustomHeader = styled.header`
  ${({ theme }) => {
    return css`
      height: 5rem;
      padding: 0 2.2rem;

      display: flex;
      background-color: ${theme.colors.background};

      .cupick_logo {
        width: 12rem;
        height: 100%;

        background: url(${(props) => props.src}) no-repeat center / contain;
        transition: all 0.4s;

        cursor: pointer;

        &:hover {
          transform: scale(1.05);
        }
      }
    `;
  }}
`;

const CustomFooter = styled.footer`
  ${({ theme }) => {
    return css`
      height: 9rem;

      display: flex;
      position: relative;

      .svg_box {
        transition: all 0.2s;
        fill: ${theme.colors.middle};
      }

      .svg_box.on {
        fill: ${theme.colors.dark};
      }
    `;
  }}
`;

const CustomFooterButton = styled.button`
  ${({ theme }) => {
    return css`
      flex: 1 1 auto;

      padding-top: 1.2rem;

      display: flex;
      justify-content: center;

      background-color: ${theme.colors.wg};

      cursor: pointer;

      &:hover svg {
        opacity: 0.7;
      }
    `;
  }}
`;

const CustomGoToCreateButton = styled.button`
  ${({ theme }) => {
    return css`
      width: 6.5rem;
      height: 6.5rem;
      border-radius: 50%;

      position: absolute;
      left: 50%;
      transform: translate(-50%, -50%);

      box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.3);

      cursor: pointer;
      overflow: hidden;

      img {
        width: 11rem;

        position: absolute;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);

        transition: all 0.5s;
        opacity: 0.9;
      }

      img:hover {
        opacity: 1;
      }
    `;
  }}
`;
dusunax commented 2 years ago

회원가입 페이지 버튼박스 오류 수정 후 재배포 예정입니다.

=> 구조 수정 및 재배포 완료

dusunax commented 2 years ago

반응형 작업

contents area 패딩

dusunax commented 2 years ago

커뮤니티 페이지 => 완료!

const CustomProfilePic = styled.div ${({ theme }) => { return css width: 1.5rem; height: 1.5rem; border-radius: 50%;

  border: 1px solid #b6b6b6;
  background: #eee
    url(${(props) =>
      props.profileImage ? props.profileImage : emptyProfilePic})
    no-repeat center / cover;
`;

}} `;

- flex 리스트
```jsx

const CustomFlexListWrap = styled.div`
  ${({ theme }) => {
    return css`
      padding: 0 2rem;

      display: flex;
      flex-flow: wrap;

      gap: ${theme.gaps.md};

      ${theme.devices.tablet} {
        gap: ${theme.gaps.base};
      }

      ${theme.devices.mobile} {
        gap: ${theme.gaps.sm};
      }

      ${theme.devices.mobileXS} {
        gap: ${theme.gaps.xs};
      }
    `;
  }}
`;

const CustomFlexList = styled.div`
  ${({ theme }) => {
    return css`
      flex: ${theme.flexItems.md};
      height: 26vh;
      max-height: 50rem;
      border-radius: 1rem;

      box-shadow: ${theme.boxShadows.base};

      transition: all 0.3s;
      overflow: hidden;

      cursor: pointer;

      ${theme.devices.tablet} {
        flex: ${theme.flexItems.base};
      }

      ${theme.devices.mobile} {
        flex: ${theme.flexItems.sm};
      }

      ${theme.devices.mobileXS} {
        flex: ${theme.flexItems.xs};
      }

      :hover {
        transform: translateY(-0.4rem);
        box-shadow: ${theme.boxShadows.hover};
      }

      & > .flex_box {
        height: 100%;

        display: flex;
        flex-flow: column;
      }
    `;
  }}
`;

const CustomIconBox = styled.div` display: flex;

gap: 0.5rem;

.icon { transition: all 0.3s; }

.icon:hover { cursor: pointer; transform: scale(1.3); } `;

dusunax commented 2 years ago

삭제한 CustomStyle

dusunax commented 2 years ago

Layout.jsx 수정

import React from "react";
import { useLocation } from "react-router-dom";

import styled from "styled-components";
import styledLayoutComponents from "../styles/customLayoutStyle";
const { CustomWrapFullVH } = styledLayoutComponents;

import Router from "../shared/Router";
import Header from "../partial/Header";
import Footer from "../partial/Footer";

const Layout = () => {
  const pathname = useLocation().pathname;

  let layoutType = { headerFooter: false, footer: false, header: false };
  let { header, footer, headerFooter } = layoutType;

  const caseHeaderFooter = ["/recipe/create/guest", "/mypage", "/profile"];
  const caseFooter = ["/recipe"];

  function handlePathname() {
    caseHeaderFooter.map((path) => {
      if (pathname.indexOf(path) > -1) {
        headerFooter = true;
        return;
      }
    });

    caseFooter.map((path) => {
      if (pathname === path) {
        footer = true;
      }
    });
  }
  handlePathname();

  return (
    <StLayout>
      {headerFooter && <Header />}

      <Router />

      {(headerFooter || footer) && <Footer pathname={pathname} />}
    </StLayout>
  );
};

export default Layout;

const StLayout = styled(CustomWrapFullVH)`
  max-width: 60rem;
  padding: 0;
  overflow: hidden;
`;
dusunax commented 2 years ago

vh관련 wrapper CustomComponent로 수정한 위치

import styledLayoutComponents from "../../styles/customLayoutStyle";
const { CustomWrapBody } = styledLayoutComponents;