엔터프라이즈 제품 디자인 · 신규 리소스

REI Cedar 디자인 시스템.

네이티브 Vue 타일, 실제 토큰 값, 완전한 키보드 탐색, 반응형 제품 구성을 사용해 구체적인 Cedar 배송 방식 선택 화면을 구현하세요.

OpenDesign 가이드7개 챕터참고 항목 37개독자적 적용 가이드
01

REI Cedar 디자인 시스템 인터페이스 미리보기

네이티브 Cedar 타일을 사용해 배송 또는 픽업을 선택할 수 있습니다. 키보드 탐색과 이용할 수 없는 옵션도 지원합니다.

수령 방법 선택전체 예시 열기
네이티브 Cedar 17.1.0 / Vue 3, 원본 구성 사용. · 구현 레퍼런스
02

REI Cedar 디자인 시스템 디자인 참조

@rei/cdr-tokens 14.0.1 REI 테마에서 추출한 값입니다. 네이티브 컴포넌트 동작은 @rei/cedar 17.1.0으로 확인했습니다.

REI 테마 색상 역할

출처
이름 / 규칙값 / 구성용도
cdr-color-background-button-primary-rest#1f513f 기본 버튼 배경색.
cdr-color-background-button-primary-hover#c7dfd1 기본 색상 호버 채우기입니다.
cdr-color-background-primary#ffffff 기본 콘텐츠 표면입니다.
cdr-color-background-secondary#F4F2ED 보조 표면입니다.
cdr-color-text-button-primary#fafbf9 기본 버튼 레이블입니다.
cdr-color-text-primary#4b4a48 본문 텍스트 역할.
cdr-color-text-secondary#736e65 보조 텍스트.
cdr-color-text-error#811823 오류 메시지 텍스트입니다.
cdr-color-border-primary#d5cfc3 기본 표면 경계입니다.
cdr-color-border-secondary#958e83 보조 테두리 역할입니다.

10px 루트에서의 간격과 모서리 반경

출처
이름 / 규칙값 / 구성용도
cdr-space-zero0Cedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-sixteenth-x0.1remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-eighth-x0.2remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-three-sixteenth-x0.3remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-quarter-x0.4remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-three-eighth-x0.6remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-half-x0.8remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-three-quarter-x1.2remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-one-x1.6remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-one-and-a-half-x2.4remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-two-x3.2remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-three-x4.8remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-space-four-x6.4remCedar 루트에서는 1rem이 10px입니다. 이를 16px 루트에 그대로 적용하지 마세요.
cdr-radius-sharp0고정된 토큰 패키지에서 가져온 모서리 형태입니다.
cdr-radius-soft0.2rem고정된 토큰 패키지에서 가져온 모서리 형태입니다.
cdr-radius-softer0.4rem고정된 토큰 패키지에서 가져온 모서리 형태입니다.
cdr-radius-softest0.6rem고정된 토큰 패키지에서 가져온 모서리 형태입니다.
cdr-radius-round999.9rem고정된 토큰 패키지에서 가져온 모서리 형태입니다.

Fulfillment 타일 API

출처
이름 / 규칙값 / 구성용도
checkedboolean선택한 방법을 반영합니다.
disabledboolean이용할 수 없는 옵션입니다. 상태를 변경할 수 없게 하세요.
roleradio | checkbox수령 방법 하나를 선택할 때는 radio를 사용합니다.
tabindex0 / -1애플리케이션에서 탭 정지 지점 하나와 화살표 키 탐색을 관리합니다.
header slotmethod label선택 항목의 이름을 읽을 수 있는 형태로 제공합니다.
body slotsupporting details배송 시간 또는 픽업 위치입니다.
footer slotprominent detail비용 또는 이용 가능 여부입니다.
icon-right slotselection indicator예시에서는 선택한 방법 옆에 확인 표시를 추가합니다.
loadingboolean헤더와 크기는 유지하고 본문과 푸터를 마스킹합니다.
03

REI Cedar 디자인 시스템 전체 가이드

실제 인터페이스를 위해 이 시스템을 선택하고 적용하고 검토하는 실용 가이드.

DESIGN-rei-cedar.md

완전한 안내와 구현 시작점, 소스 링크.

가이드 다운로드

REI Cedar 디자인 시스템 Vue 런타임 및 스타일 종속 항목

컴포넌트와 토큰을 함께 고정합니다

작동 예제는 @rei/cedar 17.1.0, @rei/cdr-tokens 14.0.1, Vue 3를 사용합니다. 컴포넌트 패키지는 모듈식 진입점을 제공합니다. 이 예제에서는 CdrButton과 CdrFulfillmentTile, 그리고 내부 표면·레이아웃·텍스트 컴포넌트에 필요한 CSS만 가져옵니다. 소스에는 모든 import가 명시되어 있습니다. JavaScript 동작만으로는 스타일이 적용된 결과를 보장할 수 없기 때문입니다.

이 OpenDesign 가이드에서

예제에서 독점 글꼴 사용하지 않기

Cedar 설치 안내에서는 컴포넌트 사용과 REI 글꼴 사용 권한을 구분합니다. 이 예제는 cdr-fonts.css나 글꼴을 포함한 통합 스타일시트를 가져오지 않습니다. 인터페이스 텍스트에는 시스템 산세리프 글꼴을, 원래 편집 스타일의 제목에는 Georgia를 사용합니다. 이러한 대체 글꼴은 애플리케이션에서 정한 것으로, REI 브랜드 서체가 아닙니다.

REI Cedar 디자인 시스템 토큰 단위와 표면 색상

Cedar 기본 스케일 사용하기

Cedar 토큰은 기본 글꼴 크기가 10px일 것으로 예상하므로 간격 16px를 1.6rem으로 나타냅니다. 기본 글꼴 크기를 16px로 설정하면 같은 값이 25.6px로 커집니다. 독립형 예제에서는 html을 62.5%로 설정하고 본문 글꼴 크기로 1.6rem을 사용합니다. 기본 글꼴 크기가 다른 호스트 제품에 통합하려면 기존 사이트에 전역 초기화 코드를 그대로 붙여 넣는 대신, 경계를 명확히 정해야 합니다.

토큰을 컴포넌트 역할에 매핑하기

기본 버튼에는 짙은 녹색의 기본 상태 채우기와 연한 녹색의 호버 상태 채우기를 사용합니다. 콘텐츠 표면과 테두리에는 따뜻한 중성색을 사용합니다. 표에는 문서 사이트 테마가 아니라 REI 테마의 의미 기반 값을 기록합니다. 그림 속 가방에는 별도로 만든 장식 색상을 사용하며, 이를 공식 Cedar 토큰 내보내기 값으로 제시하지 않습니다.

REI Cedar 디자인 시스템 배송 옵션 타일 구성

타일마다 바뀌는 선택지는 하나만 표시하기

배송 옵션 타일에는 배송 방식 이름, 소요 시간, 비용 또는 이용 가능 여부를 함께 표시합니다. 타일 안에 두 번째 인터랙티브 링크나 버튼을 넣지 않아야 합니다. 예제에서는 확인 작업을 라디오 그룹 바깥에 배치하고, 이용할 수 없는 빠른 배송 옵션에는 내용을 읽을 수 있도록 설명을 표시합니다. 헤더·본문·푸터 슬롯을 사용해 계층 구조를 명확히 합니다.

테두리 외에도 선택 상태 표시하기

선택한 방식에는 checked=true를 설정하고 icon-right 슬롯에 체크 표시를 넣습니다. 따라서 미묘한 테두리 스타일을 구분하기 어려운 경우에도 현재 선택된 항목을 알아볼 수 있습니다. 이용 가능한 옵션을 클릭하면 선택 항목만 바뀌고, 별도의 확인 단계에서 현재 선택을 확정합니다. 비활성 배송 방식은 모델을 업데이트하지 않습니다.

REI Cedar 디자인 시스템 제품 맥락과 반응형 레이아웃

상품과 선택지를 나란히 배치하기

넓은 화면에서는 직접 제작한 CSS 데이팩 그림과 상품 요약을 배송 옵션 옆에 배치합니다. 상품은 가상의 제품이며 배송 약속은 예시로 표시합니다. 이 구성은 REI 제품 사진을 복제하거나 실시간 재고 정보를 지어내지 않고 Cedar의 따뜻한 표면 색상을 보여 줍니다.

컨트롤을 줄이는 대신 레이아웃 재배치하기

REI Cedar 디자인 시스템 선택, 키보드 및 피드백

애플리케이션 수준의 라디오 동작 제공하기

타일은 라디오 의미 체계를 제공하지만, 그룹 레이블과 선택된 값, 포커스 모델은 애플리케이션이 관리합니다. 선택된 이용 가능 옵션만 탭 순서에 포함됩니다. 화살표 키로 이용 가능한 옵션을 순환하고, Home과 End로 각각 첫 번째와 마지막 옵션을 선택하며, 이용할 수 없는 빠른 배송 옵션은 건너뜁니다. 이 동작은 접근성 할 일로 남겨 두지 않고 전체 소스에 구현되어 있습니다.

이전 확인 피드백 지우기

선택을 확인하면 주문이 접수되었다고 잘못 알리지 않고 현재 상태를 로컬에 표시합니다. 선택한 타일을 바꾸면 이전 결과가 지워집니다. 상태 영역은 배송 방식 설명과 분리되어 있어, 보조 기술이 라디오의 접근성 이름을 바꾸지 않고도 피드백을 알릴 수 있습니다.

REI Cedar 디자인 시스템 전체 Vue 구현

동일한 기본 화면 구현하기

Vite Vue 프로젝트를 만들고 고정된 버전의 패키지를 설치한 다음, 아래의 전체 main.js와 cedar.css 예제를 사용합니다. 루트 요소의 이름은 root로 유지하거나, Vite 템플릿에 맞게 마운트 선택자를 변경합니다. 예제에서는 Vue 렌더 함수를 사용하므로 SFC 전처리 과정이 독자에게 숨겨지지 않습니다.

  1. 고정된 버전의 컴포넌트 및 토큰 패키지를 설치합니다.
  2. main.js에 있는 모든 CSS import를 유지합니다.
  3. 앱을 root 요소에 마운트합니다.
  4. 화살표 키로 배송 옵션을 바꾸고 로컬 결과를 확인하세요.

레이아웃을 디버깅하기 전에 스타일 확인하기

먼저 타일에 표면 스타일, 경계선, 패딩이 적용되고 버튼에 Cedar 스타일이 적용되는지 확인합니다. 인터페이스는 동작하지만 일반 텍스트처럼 보인다면 컴포넌트 CSS 및 토큰 CSS import를 확인합니다. 간격이 지나치게 크다면 기본 글꼴 크기를 살펴봅니다. 원인이 서로 다른 문제이므로 해결 방법도 다릅니다.

REI Cedar 디자인 시스템 AI 에이전트 인계 및 승인 기준

통합 경계 명시하기

독점 글꼴을 사용하지 않고 고정된 Cedar 컴포넌트와 토큰 패키지로 배송 옵션 선택기를 만드는 Vue 3 코드를 AI 에이전트에 요청합니다. 타일의 정확한 상태와 키보드 동작을 제공합니다. 실제 제품에서는 예시 배송 시간을 백엔드 계약에 따라 대체하고, 주문 작업을 활성화하기 전에 로딩과 오류를 처리합니다.

동작과 소스를 함께 검토하기

로컬 검증에서는 화살표 키 선택, 화면에 표시되는 선택 상태, 로컬 확인, 이전 결과 지우기, 좁은 화면 레이아웃을 확인합니다. 다운로드 가능한 가이드에는 미리보기와 동일한 애플리케이션 코드가 포함되어 있습니다. 네이티브 런타임 검증을 했더라도 예시 배송 약속이 실제가 되는 것은 아니며, REI 브랜드를 재사용할 권한이 생기는 것도 아닙니다.

  • 이용할 수 없는 배송 방식은 선택할 수 없습니다.
  • 선택을 바꾸면 이전 확인 결과가 지워집니다.
  • 글꼴 파일이나 서비스 호출이 필요하지 않습니다.

REI Cedar 디자인 시스템 컴포넌트 예제

main.js — 전체 Vue 배송 옵션 선택기

네이티브 컴포넌트, 로컬 상태, 순환 라디오 포커스 및 필요한 모든 스타일 import를 포함합니다.

js
import { createApp, h, ref } from "vue";
import CdrButton from "@rei/cedar/CdrButton";
import CdrFulfillmentTile from "@rei/cedar/CdrFulfillmentTile";
import "@rei/cedar/dist/cdr-reset.css";
import "@rei/cedar/dist/style/cdr-button.css";
import "@rei/cedar/dist/style/cdr-fulfillment-title.css";
import "@rei/cedar/dist/style/cdr-surface-selection.css";
import "@rei/cedar/dist/style/cdr-layout.css";

import "@rei/cdr-tokens/css";
import "@rei/cedar/dist/style/cdr-surface.css";
import "@rei/cedar/dist/style/cdr-body.css";
import "@rei/cedar/dist/style/cdr-subheading-sans.css";
import "./cedar.css";
const choices = [
  {
    id: "ship",
    label: "Ship to home",
    detail: "Sample delivery: 3–5 days",
    price: "No delivery charge",
    available: true,
  },
  {
    id: "pickup",
    label: "Pick up nearby",
    detail: "Sample location: North Trail",
    price: "Ready tomorrow",
    available: true,
  },
  {
    id: "express",
    label: "Express delivery",
    detail: "Unavailable for this sample item",
    price: "Choose another method",
    available: false,
  },
];
createApp({
  setup() {
    const selected = ref("ship"),
      result = ref("");
    function choose(id) {
      selected.value = id;
      result.value = "";
    }
    function keyboard(e, id) {
      if (
        [
          "ArrowRight",
          "ArrowDown",
          "ArrowLeft",
          "ArrowUp",
          "Home",
          "End",
        ].includes(e.key)
      ) {
        e.preventDefault();
        const ids = choices.filter((x) => x.available).map((x) => x.id);
        let next =
          e.key === "Home"
            ? ids[0]
            : e.key === "End"
              ? ids.at(-1)
              : ids[
                  (ids.indexOf(id) +
                    (e.key === "ArrowRight" || e.key === "ArrowDown"
                      ? 1
                      : ids.length - 1)) %
                    ids.length
                ];
        choose(next);
        document.getElementById("choice-" + next).focus();
      }
    }
    return () =>
      h("main", [
        h("header", [
          h("p", { class: "eyebrow" }, "OUTDOOR GEAR / ORIGINAL SPECIMEN"),
          h("h1", "Ready for the next trail"),
          h("p", "Choose a fulfillment method for this fictional daypack."),
        ]),
        h("div", { class: "composition" }, [
          h("section", { class: "product", "aria-label": "Sample product" }, [
            h("div", { class: "art", "aria-hidden": "true" }, [
              h("div", { class: "pack" }, [h("i"), h("span"), h("b")]),
            ]),
            h("div", [
              h("h2", "Ridge daypack · 24 L"),
              h("p", "A lightweight everyday pack for short outings."),
              h(
                "p",
                { class: "note" },
                "Illustrated sample product · no inventory or purchase connection",
              ),
            ]),
          ]),
          h("section", { class: "options" }, [
            h(
              "h2",
              { id: "fulfillment-label" },
              "How would you like to receive it?",
            ),
            h(
              "div",
              {
                class: "tiles",
                role: "radiogroup",
                "aria-labelledby": "fulfillment-label",
              },
              choices.map((c) =>
                h(
                  CdrFulfillmentTile,
                  {
                    id: "choice-" + c.id,
                    role: "radio",
                    tabindex: c.available && selected.value === c.id ? 0 : -1,
                    checked: selected.value === c.id,
                    disabled: !c.available,
                    "aria-label": c.label,
                    onClick: () => c.available && choose(c.id),
                    onKeydown: (e) => keyboard(e, c.id),
                  },
                  {
                    header: () => c.label,
                    "icon-right": () =>
                      selected.value === c.id
                        ? h(
                            "span",
                            {
                              "aria-hidden": "true",
                              style: "font-size:2rem;color:#1f513f",
                            },
                            "✓",
                          )
                        : null,
                    body: () => c.detail,
                    footer: () => c.price,
                  },
                ),
              ),
            ),
            h("div", { class: "review" }, [
              h(
                CdrButton,
                {
                  onClick: () => {
                    result.value = `Local selection: ${choices.find((c) => c.id === selected.value).label}. No order has been placed.`;
                  },
                },
                () => "Review selection",
              ),
              h("p", { role: "status", class: "result" }, result.value),
            ]),
          ]),
        ]),
        h(
          "footer",
          "Native Cedar 17.1.0 fulfillment tiles and button. Original composition with system-font fallback; no REI proprietary fonts or photography.",
        ),
      ]);
  },
}).mount("#root");

코드 참조

  • index.html에 <div id="root"></div>를 사용합니다.

cedar.css — 독창적인 제품 구성

반응형 레이아웃, CSS 그림, 명시적인 대체 글꼴을 포함합니다.

CSS
html {
  font-size: 62.5%;
}
body {
  margin: 0;
  color: #2e2e2b;
  background: #fafbf9;
  font:
    1.6rem/1.5 system-ui,
    sans-serif;
}
* {
  box-sizing: border-box;
}
main {
  padding: 3.2rem;
}
header {
  border-bottom: 1px solid #dcd6cb;
  margin-bottom: 3.2rem;
  padding-bottom: 2.4rem;
}
h1 {
  font:
    700 3.6rem/1.1 Georgia,
    serif;
  margin: 1.2rem 0;
}
h2 {
  font:
    700 2.2rem/1.25 system-ui,
    sans-serif;
  margin: 0 0 1.6rem;
}
p {
  margin: 0.8rem 0;
}
.eyebrow,
footer,
.note {
  font-size: 1.4rem;
  color: #4b4a48;
}
.composition {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: 4.8rem;
}
.product {
  display: grid;
  gap: 2.4rem;
  align-content: start;
}
.art {
  height: 25rem;
  background: #edeae3;
  border-radius: 0.4rem;
  display: grid;
  place-items: center;
}
.pack {
  position: relative;
  width: 12rem;
  height: 17rem;
  border-radius: 4rem 4rem 2rem 2rem;
  background: #48633c;
  border: 0.6rem solid #34492c;
  box-shadow: 2rem 1rem 0 -1.2rem #b3ad9f;
}
.pack i {
  position: absolute;
  top: -2.2rem;
  left: 3.2rem;
  width: 4.4rem;
  height: 2.4rem;
  border: 0.7rem solid #34492c;
  border-bottom: 0;
  border-radius: 1.4rem 1.4rem 0 0;
}
.pack span {
  position: absolute;
  left: 1.2rem;
  right: 1.2rem;
  bottom: 1.2rem;
  height: 7rem;
  border-radius: 1rem;
  background: #607b52;
  border-top: 0.5rem solid #34492c;
}
.pack b {
  position: absolute;
  left: 4.4rem;
  top: 4rem;
  width: 2rem;
  height: 2rem;
  background: #edeae3;
  border-radius: 50%;
}
.tiles {
  display: grid;
  gap: 1.6rem;
}
.tiles > * {
  font-family: system-ui, sans-serif !important;
}
.review {
  margin-top: 2.4rem;
}
.result {
  color: #355e28;
  font-size: 1.4rem;
  margin-top: 1.6rem;
}
footer {
  margin-top: 3.2rem;
  padding-top: 1.6rem;
  border-top: 1px solid #dcd6cb;
}
:focus-visible {
  outline: 3px solid #406eb5;
  outline-offset: 3px;
}
@media (max-width: 700px) {
  main {
    padding: 2rem;
  }
  .composition {
    grid-template-columns: 1fr;
    gap: 3.2rem;
  }
  .product {
    grid-template-columns: 12rem 1fr;
    gap: 1.6rem;
  }
  .art {
    height: 17rem;
  }
  .pack {
    transform: scale(0.7);
  }
  h1 {
    font-size: 2.8rem;
  }
  .product h2 {
    font-size: 1.8rem;
  }
}

코드 참조

  • REI 독점 글꼴 파일은 가져오지 않습니다.
04

REI Cedar 디자인 시스템 에이전트 설정

구현 시작점

미리보기는 이러한 네이티브 모듈을 로컬에 번들링합니다. 글꼴은 시스템 대체 글꼴을 사용합니다.

sh
npm create vite@latest cedar-study -- --template vue
cd cedar-study
npm install
npm install @rei/[email protected] @rei/[email protected]
# Replace src/main.js and add src/cedar.css with the complete examples.
# Change the index.html mount element to id="root".
npm run dev

프로젝트를 위한 프롬프트

에이전트 프롬프트
이 전체 소스를 사용해 Cedar 17.1.0과 tokens 14.0.1로 Vue 3 주문 수령 방식 선택기를 빌드하세요. 루트의 10px 스케일을 분리하고, 필수 컴포넌트와 토큰 CSS을 가져오며, 독점 글꼴은 피하고, 라디오 그룹 내 순환 포커스와 비활성 선택 항목을 유지하세요. 실제 재고 연동 계약이 제공될 때까지는 가상의 재고 정보를 사용하세요.
05

REI Cedar 디자인 시스템 소스 및 범위

REI Cedar에 대한 OpenDesign 가이드입니다. 예제는 Cedar 17.1.0과 tokens 14.0.1을 사용합니다. 제품, 일러스트레이션, 매장 및 배송 정보는 모두 가상이며, REI 독점 글꼴과 사진은 포함되지 않습니다.