Skip to content

Commit fdba8e8

Browse files
authored
디자인 시스템 chromatic 및 템플릿 생성 추가 (#13)
* feat: Chromatic UI 테스팅 github action 실험 적용 * feat: chromatic 설치 * feat: chromatic ci 관련 yarn->npm으로 변경 * feat: chromatic 실험용 Test 컴폰너트 ui 변경 * feat: chromatic github action 패키지 버전 수정 * feat: chromatic ci 중단 옵션 수정 * feat: upstream PR에 대해 작동하도록 수정 * feat: 크로마틱 연동 테스트 * feat: 스토리북 plop통한 템플릿 생성 기능 추가 * docs: 스토리북 Intro 문서 수정 * feat: 크로마틱 연동 upstream에 적용하도록 수정 * docs: 스토리북 Intro 스타일 수정 * docs: 프로젝트 README에 디자인시스템 배포 페이지 추가 * fix: 디자인 시스템 chromatic 연결 프로젝트 변경 다른 프로젝트랑 연결 되어 있었기에 수정. * feat: chromatic github action에서 pull request target 방식으로 수정 forked에서의 pull request로는 secret을 사용할 수 없기 때문에.
1 parent a0dca6d commit fdba8e8

File tree

13 files changed

+2464
-166
lines changed

13 files changed

+2464
-166
lines changed

.github/workflows/chromatic.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Chromatic UI Verification
2+
3+
on:
4+
pull_request_target:
5+
branches:
6+
- main # main 브랜치로의 PR 발생 시 실행
7+
types: [opened, synchronize, reopened] # PR이 열리거나, 업데이트되거나, 다시 열릴 때 실행
8+
9+
jobs:
10+
chromatic-test:
11+
# 레포와 PR유저 제한. Dependabot은 의존성 업데이트를 자동화하는 GitHub의 봇.
12+
if: github.repository == 'prography/10th-Motimo-FE' &&
13+
(
14+
github.event.pull_request.user.login == 'Hys-Lee' ||
15+
github.event.pull_request.user.login == 'devgony' ||
16+
startsWith(github.actor, 'dependabot')
17+
)
18+
19+
permissions:
20+
contents: read # 코드 체크아웃에 필요
21+
pull-requests: read # PR 정보 읽기에 필요 (pull_request_target 사용 시)
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Checkout PR code
25+
uses: actions/checkout@v4
26+
with:
27+
# PR의 최신 커밋을 가져옵니다. PR_target의 위험성을 낮춥니다.
28+
ref: ${{ github.event.pull_request.head.sha }}
29+
fetch-depth: 0 # Chromatic이 Git 히스토리를 분석할 수 있도록 함
30+
31+
- name: Setup Node.js
32+
uses: actions/setup-node@v4
33+
with:
34+
node-version: "20" # 프로젝트에 맞는 Node.js 버전
35+
36+
- name: Install dependencies
37+
run: npm install # 또는 npm install
38+
39+
- name: Build Storybook (선택 사항, 필요시)
40+
run: npm run build-storybook # 또는 npm run build-storybook
41+
42+
- name: Run Chromatic
43+
uses: chromaui/action@12.2.0
44+
with:
45+
# 👇 Chromatic 프로젝트 토큰 (Secrets에 저장 권장)
46+
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
47+
# 👇 true로 설정하면 리뷰되지 않은 변경이 있을 경우 CI를 실패시킴
48+
exitZeroOnChanges: false

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ next-env.d.ts
4949
# storybook
5050
*storybook.log
5151
storybook-static-shared
52+
storybook-static
5253

5354

5455
# local environment - vscode

.storybook/CHANGELOG.mdx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import { Meta } from "@storybook/blocks";
44

55
# Change Log
66

7-
## [0.0.1] - 2025-05-20
7+
## [0.1.0] - 2025-06-10
8+
9+
스토리북 템플릿 생성 기능 추가 및 Intro 수정
810

9-
### Started
11+
## [0.0.1] - 2025-05-20
1012

11-
- 스토리북 관리 시작
13+
스토리북 관리 시작

.storybook/Introduction.mdx

Lines changed: 111 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,71 +5,132 @@ import { Meta } from "@storybook/blocks";
55
# **MOTIMO Design System**
66

77
<br />
8-
## 사용가이드
98

10-
[스토리북 배포 주소 나중에 설정]
9+
## 1. 스토리북 둘러보기
1110

12-
<br />
11+
### 배포
1312

14-
## 작성법
13+
<a href="10th-motimo-storybook.vercel.app">10th-motimo-storybook.vercel.app</a>
1514

16-
#### 스토리
15+
### 사용법
1716

18-
- 기본 스토리 사용 방식을 따른다.
17+
- 사이드바에서 원하는 컴포넌트를 선택합니다.
1918

20-
- title을 통해 사이드바의 디렉토리를 구성한다.
19+
- **Docs** 통해 컴포넌트 전체 정보를 한 눈에 볼 수 있습니다.
2120

22-
- 사용법은 다음과 같다.
21+
- 스토리별 탭은 Control, Actions, Design, Interactions, Visual tests가
22+
존재합니다.
2323

24-
```typescript
25-
// Test.stories.tsx
26-
import Test from "./Test";
27-
import { StoryObj } from "@storybook/react";
24+
- **Controls 탭**에서 Props 값을 확인 또는 변경해볼 수 있습니다. 각 Prop에
25+
대한 설명도 이곳에서 볼 수 있습니다.
2826

29-
// meta는 공통 옵션.
30-
const meta = {
31-
title: "Example/Test",
32-
component: Test,
33-
args: {
34-
children: "asdf",
35-
},
36-
};
37-
export default meta;
38-
39-
type Story = StoryObj<typeof meta>;
40-
41-
// Primary는 공통. argTypes를 사용해 상호작용 가능하도록 한다.
42-
export const Primary: Story = {
43-
argTypes: {
44-
children: {
45-
control: "text",
46-
description: "보통은 텍스트를 입력하겠지",
47-
table: {
48-
category: "이야호",
49-
},
50-
},
51-
},
52-
args: {
53-
children: "버튼",
54-
},
55-
};
27+
- **Actions 탭**에서 이벤트 핸들러(콜백 함수)가 호출될 때 발생하는 동작을
28+
기록하고 시각적으로 볼 수 있습니다.
5629

57-
// 기타 스토리들은 args를 기본으로 간단히 처리함
58-
export const Ex1: Story = {
59-
args: {
60-
children: "기본값",
61-
},
62-
};
63-
```
30+
- **Design 탭**에서 실제 figma에 작성된 컴포넌트 디자인을 볼 수 있습니다.
31+
스토리북에 등록된 컴포넌트와 비교해보세요.
6432

65-
#### 자동화
33+
- **Interactions 탭**에서 각 스토리별 play함수에 등록된 상호작용 테스트 결과를
34+
확인할 수 있습니다.
6635

67-
plop.js를 사용해서 추후 story들 자동 생성 예정.
36+
- **Visual test 탭**에서 Chromatic과 연결해 컴포넌트 디자인 변경을 리뷰받을 수
37+
있습니다. 변화가 unreviewed시 PR되지 않으니 주의하세요.
38+
39+
<br />
40+
사용을 위해선 Story작성 시 이벤트 핸들러 props에 함수를 주입하면 됩니다.
41+
<br />
42+
43+
## 2. 스토리 작성 가이드 (기여자를 위한 안내)
44+
45+
### 스토리 파일 작성법 (`*.stories.tsx`)
46+
47+
- `npm run generate:story` 혹은 `npm run generate:story {컴포넌트 경로}`를 통해 컴포넌트의 스토리북 템플릿을 생성한다.
48+
49+
- **필수로, meta의 title을 스토리북 사이드바에 맞게 적절히 수정해야 한다**
50+
51+
- argTypes 필드를 직접 작성하지 않으면, 컴포넌트 props에 대한 type 및 interface를 보고 자동 등록됩니다.
52+
53+
```typescript
54+
interface TestProps {
55+
/**discription입니다*/
56+
children: ReactNode;
57+
}
58+
59+
const Test = ({children}:TestProps)=>{
60+
...
61+
}
62+
```
63+
64+
- 선택적으로 커스텀 할 수 있으며, 이를 위한 내부 코드는 아래와 같이 구성된다.
65+
66+
```typescript
67+
// Test.stories.tsx
68+
import Test from "./Test";
69+
import { StoryObj } from "@storybook/react";
70+
71+
/**
72+
* 1. meta는 컴포넌트별 공통 옵션입니다.
73+
*/
74+
const meta = {
75+
title: "Components/Test", // Storybook 사이드바 경로 (프로젝트 규칙에 맞게 수정)
76+
component: Test, // 컴포넌트 등록
77+
parameters: {
78+
// Canvas 레이아웃을 중앙으로 정렬하거나 패딩을 추가할 수 있습니다.
79+
layout: "centered",
80+
},
81+
// Docs 탭 자동 생성을 위해 필요합니다.
82+
tags: ["autodocs"],
83+
// Controls Addon에서 Props를 어떻게 제어할지, 설명을 추가합니다.
84+
// 모든 스토리에 적용될 기본 Props (선택 사항)
85+
args: {
86+
// 예시: label: '라벨',
87+
},
88+
} satisfies Meta<typeof Test>;
89+
90+
export default meta;
91+
92+
type Story = StoryObj<typeof meta>;
93+
94+
/**
95+
* 2. 개별 스토리 작성: 컴포넌트의 다양한 상태와 예시를 보여줍니다.
96+
97+
* 기본 UI variants들을 스토리로 작성하지만, edge case들을 작성할 수도 있습니다.
98+
99+
* 각 스토리에 맞는 args를 작성하는 것을 기본으로 합니다.
100+
*/
101+
102+
// Primary: 가장 기본적인 스토리, 필수로 존재해야 합니다.
103+
// 반드시 argTypes가 존재해야 합니다. (수기로 작성하든, 비워서 자동완성 시키든)
104+
export const Primary: Story = {
105+
argTypes: {
106+
children: {
107+
control: "text",
108+
description: "텍스트로 입력 될 것임.",
109+
table: {
110+
category: "이야호",
111+
},
112+
},
113+
},
114+
115+
// argTypes가 존재할 때, args는 기본값의 역할을 합니다.
116+
args: {
117+
children: "버튼",
118+
},
119+
};
120+
121+
// UI variatns들을 스토리로 생성합니다.
122+
// 추가적인 스토리 예시:
123+
export const LongText: Story = {
124+
args: {
125+
children: "동해물과백두산이마르고닳도록하느님이보우하사우리나라만세",
126+
},
127+
};
128+
```
68129

69130
## 디자인 토큰
70131

71-
디자인 토큰 스토리북 반영 추후 예정
132+
디자인 토큰 스토리북 Introduction 소개에 반영 추후 예정
72133

73134
## 버전
74135

75-
[0.0.1] - 2025-05-21
136+
[0.1.0] - 2025-06-10

.storybook/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@ const config: StorybookConfig = {
2424
"@storybook/addon-docs",
2525
"@storybook/addon-designs",
2626
"@storybook/addon-interactions",
27+
"@chromatic-com/storybook",
2728
],
2829
framework: {
2930
name: "@storybook/nextjs",
3031
options: {},
3132
},
3233
staticDirs: [path.resolve(__dirname, "../public")],
34+
typescript: {
35+
reactDocgen: "react-docgen-typescript",
36+
},
3337
};
3438
export default config;

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99

1010
## ✨ Motimo 프론트엔드 레포지토리에 오신 것을 환영합니다!
1111

12+
> 디자인 시스템 배포 페이지
13+
14+
<a href="10th-motimo-storybook.vercel.app">10th-motimo-storybook.vercel.app</a>
15+
1216
## 🚀 Motimo 프론트엔드의 핵심 목표
1317

1418
## 🛠️ 기술 스택

chromatic.config.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"onlyChanged": true,
3+
"projectId": "Project:6845878ba6d5224aab43a4b2",
4+
"zip": true
5+
}

components/shared/Test.stories.tsx

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,49 @@
1-
// Test.stories.tsx
2-
import Test from "./Test";
3-
import { StoryObj } from "@storybook/react";
1+
// plop-templates/story.tsx.hbs
2+
import type { Meta, StoryObj } from "@storybook/react";
3+
import Test from "./Test"; // 실제 컴포넌트 파일 임포트
44

5-
// meta는 공통 옵션.
65
const meta = {
7-
title: "Example/Test",
6+
title: "Components/Test", // Storybook 사이드바 경로 (프로젝트 규칙에 맞게 수정)
87
component: Test,
9-
args: {
10-
children: "asdf",
8+
parameters: {
9+
// Canvas 레이아웃을 중앙으로 정렬하거나 패딩을 추가할 수 있습니다.
10+
layout: "centered",
1111
},
12-
};
12+
// Docs 탭 자동 생성을 위해 필요합니다.
13+
tags: ["autodocs"],
14+
// Controls Addon에서 Props를 어떻게 제어할지, 설명을 추가합니다.
15+
// argTypes: {
16+
// // 예시: backgroundColor: { control: 'color', description: '컴포넌트 배경색' },
17+
// },
18+
// 모든 스토리에 적용될 기본 Props (선택 사항)
19+
// args: {
20+
// // 예시: label: 'Test',
21+
// },
22+
} satisfies Meta<typeof Test>;
23+
1324
export default meta;
1425

1526
type Story = StoryObj<typeof meta>;
1627

17-
// Primary는 공통. argTypes를 사용해 상호작용 가능하도록 한다.
28+
// 가장 기본적인 Primary 스토리 (필수 권장)
1829
export const Primary: Story = {
19-
argTypes: {
20-
children: {
21-
control: "text",
22-
description: "보통은 텍스트를 입력하겠지",
23-
table: {
24-
category: "이야호",
25-
},
26-
},
30+
args: {
31+
// Primary 스토리에만 적용될 Props
32+
children: "123",
2733
},
34+
};
35+
/*
36+
// 추가적인 스토리 예시:
37+
export const Secondary: Story = {
2838
args: {
29-
children: "버튼",
39+
label: 'Secondary Test',
3040
},
3141
};
3242
33-
// 기타 스토리들은 args를 기본으로 간단히 처리함
34-
export const Ex1: Story = {
43+
export const Large: Story = {
3544
args: {
36-
children: "기본값",
45+
size: 'large',
46+
label: 'Large Test',
3747
},
3848
};
49+
*/

components/shared/Test.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { ReactNode } from "react";
22

3-
const Test = ({ children }: { children: ReactNode }) => {
3+
interface TestProps {
4+
/**discription입니다*/
5+
children: ReactNode;
6+
}
7+
8+
const Test = ({ children }: TestProps) => {
49
return (
510
<>
6-
<button>{children}</button>
11+
<button className="bg-gray-300">{children}</button>
712
</>
813
);
914
};

0 commit comments

Comments
 (0)