Flower Delivery Website 구현: (3)UI 컴포넌트 구현 /TextIconButton, Checkbox

김 주현·2023년 8월 8일
0

TextIconButton

import React from "react";

import { ReactComponent as LeftIcon } from "@Static/Icons/west_300_opsz24.svg";
import { ReactComponent as RightIcon } from "@Static/Icons/east_wght300_opsz24.svg";

type TextIconButtonProp = {
  disabled?: boolean;
  leftIcon?: boolean;
  rightIcon?: boolean;
  children?: React.ReactNode;
};

const TextIconButton = ({
  disabled = false,
  leftIcon = false,
  rightIcon = false,
  children,
}: TextIconButtonProp) => {
  const iconStyle = "w-m24 aspect-square " + "tablet:w-t24 desktop:w-d24";

  const shapeStyle = "links text-black ";
  const layoutStyle =
    "relative flex flex-row place-content-center place-items-center w-fit gap-m4 " +
    "tablet:gap-t4 desktop:gap-d4 ";
  const beforeHoverStyle =
    "pointerhover:hover:before:content-[''] " +
    "pointerhover:hover:before:absolute " +
    "pointerhover:hover:before:left-0 " +
    "pointerhover:hover:before:bottom-0 " +
    "pointerhover:hover:before:w-full " +
    "pointerhover:hover:before:h-[0.31vw] " +
    "pointerhover:hover:before:bg-black " +
    "tablet:pointerhover:hover:before:h-[0.13vw] " +
    "desktop:pointerhover:hover:before:h-[0.06vw] ";
  const beforeActiveStyle =
    "active:before:content-[''] " +
    "active:before:absolute " +
    "active:before:left-0 " +
    "active:before:bottom-0 " +
    "active:before:w-full " +
    "active:before:h-[0.31vw] " +
    "active:before:bg-black " +
    "tablet:active:before:h-[0.13vw] " +
    "desktop:active:before:h-[0.06vw] ";
  const stateStyle =
    beforeHoverStyle +
    beforeActiveStyle +
    "disabled:text-gray disabled:pointerhover:hover:before:content-none " +
    "active:text-black active:pointerhover:hover:text-black " +
    "pointerhover:hover:text-gray ";

  const buttonStyle = shapeStyle + layoutStyle + stateStyle;

  return (
    <button disabled={disabled} className={buttonStyle}>
      {leftIcon && <LeftIcon className={iconStyle} />}
      {children}
      {rightIcon && <RightIcon className={iconStyle} />}
    </button>
  );
};

export default TextIconButton;

디자이너 분이 디자인을 참... 애매하게 하셨다. 나였으면 아이콘까지 색을 바꿨을 텐데, 아이콘의 변화는 없다. 아참, 그리고 hover 이슈가 있었는데, 이 포스팅으로 갈무리하겠다.

Checkbox

import React from "react";

import { ReactComponent as CheckIcon } from "@Static/Icons/check_FILL0_wght300_GRAD0_opsz24.svg";

type CheckboxProp = {
  active?: boolean;
  text: string;
  selected?: boolean;
};

const Checkbox = ({ text, active = true, selected = true }: CheckboxProp) => {
  const checkboxShapeStyle =
    "appearance-none bg-lightgray border border-black ";
  const checkboxLayoutStyle =
    "peer aspect-square " + "w-m24 h-m24 " + "tablet:w-t24 desktop:w-d24 ";
  const checkboxStateStyle =
    "disabled:border-darkgray " +
    `checked:bg-[url('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTkuNTUxNTYgMTcuNjQ5Nkw0LjIyNjU2IDEyLjMyNDZMNS4yNzY1NiAxMS4yNDk2TDkuNTUxNTYgMTUuNTI0NkwxOC43MjY2IDYuMzQ5NjFMMTkuNzc2NiA3LjQyNDYxTDkuNTUxNTYgMTcuNjQ5NloiLz48L3N2Zz4NCg==')] ` +
    "checked:bg-[length:100%_100%] " +
    (!active && selected
      ? "checked:bg-[url('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik05LjU1MTU2IDE3LjY0OTZMNC4yMjY1NiAxMi4zMjQ2TDUuMjc2NTYgMTEuMjQ5Nkw5LjU1MTU2IDE1LjUyNDZMMTguNzI2NiA2LjM0OTYxTDE5Ljc3NjYgNy40MjQ2MUw5LjU1MTU2IDE3LjY0OTZaIiBmaWxsPSIjODA4MDgwIi8+Cjwvc3ZnPg==')] "
      : "");

  const checkboxStyle =
    checkboxShapeStyle + checkboxLayoutStyle + checkboxStateStyle;

  return (
    <>
      <label
        className="flex w-fit flex-row gap-m12 tablet:gap-t12 desktop:gap-d12"
        htmlFor={text}
      >
        <input
          disabled={!active}
          className={checkboxStyle}
          checked={!active ? selected : undefined}
          type="checkbox"
          id={text}
          name={text}
        />
        <p className="caption peer-disabled:text-gray">{text}</p>
      </label>
    </>
  );
};

export default Checkbox;

의외로 많이 어려웠던 Checkbox. 심지어 이거 실무에서 사용하려면 value랑 이벤트랑 또 다르게 바꿔줘야 해서 진짜 껍데기인 것 .... 😇

어려웠던 부분

  • SVG파일 관련
  1. 나는 svg파일을 svgr plugin을 이용해서 컴포넌트화 했는데, 이걸 background-image로 넣는 법을 몰랐다.
  2. 그래서 svg코드 그대로 넣으면 된다는 말을 듣고 해봤는데, 안 됐다.
    • 왜 안 됐냐면, tailwind에서 값은 띄어쓰기를 쓰면 안 된다는 걸 개삽질 후에 알았다. 스페이스(whitespace)는 모두 _로 처리해줘야 했다.
  3. 대안으로 Base64 인코딩을 통해서 넣어줬다. 성공!
  4. 그런데 disabled시 이 svg의 색을 바꿔줘야 했는데, 이게 쉽지 않았다.
  5. filter로 가능하지 않을까 했는데, 의외로 특정 색으로 바꾸는 filter는 존재하지 않았따.
  6. 또, tailwind는 동적으로 생성한 스타일은 적용되지 않는다.
  7. 이것때문에 또 개삽질하다가, 결국 svg 코드에 fill을 넣어서 새로운 Base64 인코딩을 한 뒤 배경 이미지를 갈아끼우는 방식을 선택했다. 이게 맞냐?
  • aspect-ratio 관련
  1. 내가 겪은 현상이 aspect-ratio에 관한 건지, 아니면 브라우저 마다 DOM Tree를 구성하는 방법에 관련한 건지 잘 모르겠지만, 아마 후자가 아닐까 싶다. 아닌가?
  2. 내가 겪은 현상은, width를 설정해준 다음에 height는 aspect-ratio로 1/1 비율을 맞춰주었다. 크롬에선 잘 되는데, 사파리에선 동작하지 않았다.
  3. aspect-ratio의 browser compatibility를 확인해봤지만 호환 가능한 속성이었다.
    • 이때 약간 삼천포로 빠져서, @supports not 쿼리를 이용해서 aspect-ratio: 1/1를 지원하지 않으면 height를 따로 설정해주는 tailwind 문법을 계속 검색해보고 있었다.
    • 근데 tailwind에서 @supports는 supports-[]로 지원함시롱 @supports not ()은 지원하지 않더라.
    • 공식문서를 읽어보니, addVariant를 이용해서 plugin을 만들어 사용해라! 라고 해서 supports-not이라는 arbitrary variants를 만들어서 하려고 했는데 디지게 안 되더라
    • 머가 문제야! 이러고 공식 문서에 있는 예제 그대로 가져다가 썼는데도 작동이 안 되는 걸 보고, 걍 플러그인이 문제였군 싶었다. 왜 안 돌아가는지는 아직도 불명(ㅋㅋ)
  4. 결국 height를 설정해주었다. aspect-ratio는 왜 안 먹는 건지 아직도 모르겠다~
    • 꼼수를 알아내긴 했다. height: calc(width * 9/16) 뭐 이런 느낌인데, 나중에 1/1 비율이 아닐 때 써먹어봐야 겠다.
profile
FE개발자 가보자고🥳

0개의 댓글