24/06/17 - 이든/ KHCDS 성공 기원 1일차

Intro

  1. 발표하기 전에 이전에 다뤘던 FSD는 다가오는 문제(디자인 시스템)가 더 급하다는 자기합리화를 하며…

    머나먼 미래로,,,(아직 리펙을 못했어요ㅠㅠ)

  2. 번역 배포 전가하기는 실패로…(IP No answer…)

오늘 발표자료는 FEconf영상, 유료 강의, ‘이든 뇌피셜’의 결합입니다..

디자인 시스템

Untitled

차크라: 오픈소스를 활용하는 개발자들이 유연하게 사용할 수 있는 라이브러리

스펙트럼: 어도비 제품군에 사용될 목적

디자인 토큰

6.png

Figma Variables을 진실의 원천으로 해서 출처를 한 곳으로 통일하자

아토믹 디자인이 혼란스러운 이유

컴포넌트만을 분류해서 달성하려 하면 실패한다

  • 형태적 Atomic을 제공하는 스타일시트
  • 기능적 Atomic을 제공하는 Headless 컴포넌트

분리해서 바라봐야 무엇이 Atom인가에 대한 혼란이 사라진다.

디자인 시스템의 구조는?

  • 원칙 : 디자인과 개발의 핵심 가치 및 지침 (ex. chakra디자인 원칙)
  • 테마 : 색상, 타이포그래피, 그리드, 스페이싱 같은 디자인 요소에 대한 지침 ⇒ CSS Variable을 이용해서 모든 css 프레임 워크 내에서 동작하도록 css로 제공 (ex. 어도비 디자인 시스템)
  • 컴포넌트 : 버튼, 입력란, 탭, 모달 등 재사용 가능한 UI요소의 라이브러리 ⇒ React 기반으로 (Next, Remix, …) ⇒ zero-runtime stylesheet를 사용 (uanilla-extract) ⇒ 기능(headless ui)과 형태(디자인 토큰)를 분리
  • 패턴 : 여러 컴포넌트를 결합하여 만들어진 복잡한 사용자 인터페이스 요소 ⇒ 합성 컴포넌트로 구현
  • 도구 및 유틸리티 : 디자인 시스템을 실제 제품에 통합하기 위한 도구와 플러그인
  • 문서화 : 디자인 시스템의 모든 요소를 사용하는 방법 문서화 ⇒ 스토리북
  • 가이드라인 : 좋은 사용성, 접근성 등의 가이드와 권장사항들
  • 프로세스 및 워크플로우 : 디자인 시스템 업데이트, 확장하는 것에 대한 프로세스(검토, 승인, … ) ⇒ 모노레포

디자인을 코드로

테마는 어떻게 만들까?

라이브러리를 만들때 어려운 것은 타겟이 불명확해서 여러 상황을 고려해야 한다

commonJS VC ES module

JS VC TS

즉, x.cjs, x.mjs, type.d.ts 를 만들어 줘야한다.

라이브러리는 브라우저(핫리로딩, 플러그인, …)와 달리 모듈 번들러의 속도, 최적화에 포커스를 맞춰야 한다.

따라서 css Variable을 통해서 각각의 테마를 모듈로 만들어서 모듈 번들러를 통해 빌드시에 생성하면 좋을 듯

TMI)

모듈 번들러로 esbuild를 사용하면 빠르게 빌드할 수 있다.

  • esbuild는 매우 빠른 빌드 속도를 가지고 있다. (webpack 5보다 100배 정도 빠르다고 소개하고 있음)
    • go로 작성됨
    • 코드 파싱, 출력, 소스맵 생성 등을 병렬로 처리함
    • 불필요한 데이터 변환, 할당 과정이 없음
  • vite도 사전 번들링을 esbuild 기반으로 동작함
    • 근데 인프라, 플러그인들의 제약이 있어서 product빌드시에는 rollup 사용한다고 함

현재 우리는 css variable을 통해 변수를 만들고 사용하고 있다.

하지만 매번 사용할 때 이 변수명을 기억해서 string으로사용해야 하는불편함이 있다.

⇒ 이거를 JS object로 만들어서 사용하면 추론도 되고 가독성도 향상될 것이다.

⇒ 이랬을경우 문제 동일한 속성을 css, js이렇게 관리의 주체가 두곳으로 분산되기 때문에 유지보수가 불편하다

⇒ 이거를 해결하기 위해 js기반으로 css를 만들도록 스크립트를 작성할 수 있다.

⇒ 매도 먼저 맞는게 덜 아플 수 있다ㅎ

  • 스트립트 작업 예시

    // color token (lightColor.js)
    export const whiteAlpha = {
      50: "rgba(255, 255, 255, 0.04)",
      100: "rgba(255, 255, 255, 0.06)",
      200: "rgba(255, 255, 255, 0.08)",
      300: "rgba(255, 255, 255, 0.16)",
      400: "rgba(255, 255, 255, 0.24)",
      500: "rgba(255, 255, 255, 0.36)",
      600: "rgba(255, 255, 255, 0.48)",
      700: "rgba(255, 255, 255, 0.64)",
      800: "rgba(255, 255, 255, 0.80)",
      900: "rgba(255, 255, 255, 0.92)",
    };
    
    export const blackAlpha = {
      50: "rgba(0, 0, 0, 0.04)",
      100: "rgba(0, 0, 0, 0.06)",
      200: "rgba(0, 0, 0, 0.08)",
      300: "rgba(0, 0, 0, 0.16)",
      400: "rgba(0, 0, 0, 0.24)",
      500: "rgba(0, 0, 0, 0.36)",
      600: "rgba(0, 0, 0, 0.48)",
      700: "rgba(0, 0, 0, 0.64)",
      800: "rgba(0, 0, 0, 0.80)",
      900: "rgba(0, 0, 0, 0.92)",
    };
    
    // js object -> css variable 을 위한 스크립트
    
    import * as theme from "../dist/index.js";
    import fs from "fs";
    
    // 만들 형식 : theme.css
    // :root {
    //   --gray-900: #171923
    // }
    
    // 정규표현식으로 카멜케이스 => 변경
    const toCssCasting = (str) => {
    	...
    };
    
    // 원하는 형태로 key : value 매핑
    const cssVariables = (colorValue) =>
      Object.entries(colorValue)
        .map(([mainKey, mainValue]) =>
          Object.entries(mainValue)
            .map(
              ([subKey, subValue]) =>
                `--${toCssCasting(mainKey)}-${toCssCasting(subKey)}: ${subValue};`
            )
            .join("\n")
        )
        .join("\n");
    
    const generateThemeCssVariables = () => {
      const cssString = [];
    
      Object.entries(theme.vars).forEach(([key, value]) => {
        const selector = ":root";
        if (key === "colors") {
          Object.entries(value.$static).forEach(([colorKey, colorValue]) => {
            if (colorKey === "light") {
              return cssString.push(`${selector} {\n${cssVariables(colorValue)}\n}`);
            }
            if (colorKey === "dark") {
              const selectorDark = selector + " .theme-dark";
              return cssString.push(`${selectorDark} {\n${cssVariables(colorValue)}\n}`);
            }
            return;
          });
          return;
        }
    
        return cssString.push(`${selector} {\n${cssVariables(value)}\n}`);
      });
      return cssString;
    };
    
    const generateThemeCSS = () => {
      const variables = generateThemeCssVariables();
      fs.writeFileSync("dist/themes.css", [...variables].join("\n"));
    };
    
    generateThemeCSS();
    
    
    // build결과물 (light.d.ts)
    
    export declare const whiteAlpha: {
      50: string;
      100: string;
      200: string;
      300: string;
      400: string;
      500: string;
      600: string;
      700: string;
      800: string;
      900: string;
    };
    
    export declare const blackAlpha: {
      50: string;
      100: string;
      200: string;
      300: string;
      400: string;
      500: string;
      600: string;
      700: string;
      800: string;
      900: string;
    };
    
    // build결과물 (theme.css)
    
    :root {
    --black-alpha-50: rgba(0, 0, 0, 0.04);
    --black-alpha-100: rgba(0, 0, 0, 0.06);
    --black-alpha-200: rgba(0, 0, 0, 0.08);
    --black-alpha-300: rgba(0, 0, 0, 0.16);
    --black-alpha-400: rgba(0, 0, 0, 0.24);
    --black-alpha-500: rgba(0, 0, 0, 0.36);
    --black-alpha-600: rgba(0, 0, 0, 0.48);
    --black-alpha-700: rgba(0, 0, 0, 0.64);
    --black-alpha-800: rgba(0, 0, 0, 0.80);
    --black-alpha-900: rgba(0, 0, 0, 0.92);
    --white-alpha-50: rgba(255, 255, 255, 0.04);
    --white-alpha-100: rgba(255, 255, 255, 0.06);
    --white-alpha-200: rgba(255, 255, 255, 0.08);
    --white-alpha-300: rgba(255, 255, 255, 0.16);
    --white-alpha-400: rgba(255, 255, 255, 0.24);
    --white-alpha-500: rgba(255, 255, 255, 0.36);
    --white-alpha-600: rgba(255, 255, 255, 0.48);
    --white-alpha-700: rgba(255, 255, 255, 0.64);
    --white-alpha-800: rgba(255, 255, 255, 0.80);
    --white-alpha-900: rgba(255, 255, 255, 0.92);
    

참고

당근 디자인시스템 youtube : https://youtube.com/watch?v=obQvttzgSzY&si=16cyK-wslzVv8P4t

1편 : https://yozm.wishket.com/magazine/detail/2537/ 2편 : https://yozm.wishket.com/magazine/detail/2538/

패캠 유료강의(당근 디자인 시스템 참여하신 분) headless ui : https://headlessui.com/

쿠키런 복잡한ui 제어 : https://youtube.com/watch?v=Hv_PhrfwerQ&si=OpjA6VwkmcUXcYrh flex 디자인시스템 : https://youtube.com/watch?v=21eiJc90ggo&si=g1QmQL0hbuBZTPzQ

댓글남기기