@channeulparks/woorido-skills 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/bin/cli.js +180 -0
- package/package.json +35 -0
- package/templates/.agent/workflows/api-hook.md +134 -0
- package/templates/.agent/workflows/component.md +117 -0
- package/templates/.agent/workflows/django-view.md +193 -0
- package/templates/.agent/workflows/form.md +196 -0
- package/templates/.agent/workflows/mybatis.md +182 -0
- package/templates/.agent/workflows/page.md +161 -0
- package/templates/.agent/workflows/spring-api.md +179 -0
- package/templates/.agent/workflows/test.md +167 -0
- package/templates/.claude/skills/woorido/SKILL.md +350 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# woorido-skills
|
|
2
|
+
|
|
3
|
+
WooriDo AI Coding Rules for Claude, Gemini, Antigravity and other AI coding assistants.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx woorido-skills install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This will install:
|
|
12
|
+
- `.claude/skills/woorido/SKILL.md` - Unified coding rules
|
|
13
|
+
- `.agent/workflows/*.md` - Antigravity slash commands
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Antigravity (Primary)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
/component Button # Create WDS React component
|
|
21
|
+
/api-hook challenge # Create React Query hook
|
|
22
|
+
/form CreateChallenge # Create react-hook-form + zod form
|
|
23
|
+
/page ChallengeDetail # Create page component
|
|
24
|
+
/test Button # Create Vitest tests
|
|
25
|
+
/spring-api Challenge # Create Spring Boot API
|
|
26
|
+
/mybatis Challenge # Create MyBatis mapper
|
|
27
|
+
/django-view Search # Create Django DRF viewset
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### VS Code Gemini
|
|
31
|
+
|
|
32
|
+
Reference the skill file in your prompt:
|
|
33
|
+
```
|
|
34
|
+
@.claude/skills/woorido/SKILL.md 참고해서 Button 컴포넌트 만들어줘
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Claude Code
|
|
38
|
+
|
|
39
|
+
Skills are automatically loaded from `.claude/skills/`.
|
|
40
|
+
|
|
41
|
+
## Tech Stack
|
|
42
|
+
|
|
43
|
+
### Frontend
|
|
44
|
+
- React 18 + Vite + TypeScript
|
|
45
|
+
- WDS (WooriDo Design System) - CSS Modules + CSS Variables
|
|
46
|
+
- React Query (server state) + Zustand (client state)
|
|
47
|
+
- react-hook-form + zod
|
|
48
|
+
- Radix UI
|
|
49
|
+
|
|
50
|
+
### Backend
|
|
51
|
+
- Spring Boot 3.2 + Java 21 + MyBatis + Oracle
|
|
52
|
+
- Django 5.0 + DRF + Elasticsearch
|
|
53
|
+
|
|
54
|
+
## Available Workflows
|
|
55
|
+
|
|
56
|
+
| Command | Description |
|
|
57
|
+
|---------|-------------|
|
|
58
|
+
| `/component` | WDS-based React component |
|
|
59
|
+
| `/api-hook` | React Query hook |
|
|
60
|
+
| `/form` | Form with validation |
|
|
61
|
+
| `/page` | Page component |
|
|
62
|
+
| `/test` | Vitest tests |
|
|
63
|
+
| `/spring-api` | Spring Boot REST API |
|
|
64
|
+
| `/mybatis` | MyBatis mapper + XML |
|
|
65
|
+
| `/django-view` | Django REST viewset |
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* WooriDo Skills CLI
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx woorido-skills install
|
|
8
|
+
* npx woorido-skills install --dry-run
|
|
9
|
+
* npx woorido-skills list
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
16
|
+
const TARGET_DIR = process.cwd();
|
|
17
|
+
|
|
18
|
+
// ANSI colors
|
|
19
|
+
const colors = {
|
|
20
|
+
green: (text) => `\x1b[32m${text}\x1b[0m`,
|
|
21
|
+
yellow: (text) => `\x1b[33m${text}\x1b[0m`,
|
|
22
|
+
blue: (text) => `\x1b[34m${text}\x1b[0m`,
|
|
23
|
+
red: (text) => `\x1b[31m${text}\x1b[0m`,
|
|
24
|
+
dim: (text) => `\x1b[2m${text}\x1b[0m`,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Copy files recursively
|
|
29
|
+
*/
|
|
30
|
+
function copyRecursive(src, dest, dryRun = false) {
|
|
31
|
+
const files = [];
|
|
32
|
+
|
|
33
|
+
function walk(srcPath, destPath) {
|
|
34
|
+
const entries = fs.readdirSync(srcPath, { withFileTypes: true });
|
|
35
|
+
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
const srcFile = path.join(srcPath, entry.name);
|
|
38
|
+
const destFile = path.join(destPath, entry.name);
|
|
39
|
+
|
|
40
|
+
if (entry.isDirectory()) {
|
|
41
|
+
if (!dryRun && !fs.existsSync(destFile)) {
|
|
42
|
+
fs.mkdirSync(destFile, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
walk(srcFile, destFile);
|
|
45
|
+
} else {
|
|
46
|
+
files.push({
|
|
47
|
+
src: srcFile,
|
|
48
|
+
dest: destFile,
|
|
49
|
+
relativeDest: path.relative(TARGET_DIR, destFile),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (!dryRun) {
|
|
53
|
+
const destDir = path.dirname(destFile);
|
|
54
|
+
if (!fs.existsSync(destDir)) {
|
|
55
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
fs.copyFileSync(srcFile, destFile);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
walk(src, dest);
|
|
64
|
+
return files;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Install command
|
|
69
|
+
*/
|
|
70
|
+
function install(options = {}) {
|
|
71
|
+
const { dryRun = false } = options;
|
|
72
|
+
|
|
73
|
+
console.log();
|
|
74
|
+
console.log(colors.blue('🚀 WooriDo Skills Installer'));
|
|
75
|
+
console.log();
|
|
76
|
+
|
|
77
|
+
if (dryRun) {
|
|
78
|
+
console.log(colors.yellow('📋 Dry run mode - no files will be created'));
|
|
79
|
+
console.log();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const files = copyRecursive(TEMPLATES_DIR, TARGET_DIR, dryRun);
|
|
83
|
+
|
|
84
|
+
console.log(colors.dim('Installing files:'));
|
|
85
|
+
console.log();
|
|
86
|
+
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
console.log(` ${colors.green('✔')} ${file.relativeDest}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log();
|
|
92
|
+
console.log(colors.green(`✨ Done! ${files.length} files installed.`));
|
|
93
|
+
console.log();
|
|
94
|
+
console.log(colors.dim('Installed:'));
|
|
95
|
+
console.log(colors.dim(' - .claude/skills/woorido/SKILL.md (unified coding rules)'));
|
|
96
|
+
console.log(colors.dim(' - .agent/workflows/*.md (Antigravity commands)'));
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(colors.blue('Usage:'));
|
|
99
|
+
console.log(' Antigravity: /component Button, /api-hook challenge, etc.');
|
|
100
|
+
console.log(' VS Code Gemini: @.claude/skills/woorido/SKILL.md');
|
|
101
|
+
console.log();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* List command
|
|
106
|
+
*/
|
|
107
|
+
function list() {
|
|
108
|
+
console.log();
|
|
109
|
+
console.log(colors.blue('📦 WooriDo Skills'));
|
|
110
|
+
console.log();
|
|
111
|
+
|
|
112
|
+
console.log(colors.dim('Unified SKILL.md:'));
|
|
113
|
+
console.log(' .claude/skills/woorido/SKILL.md');
|
|
114
|
+
console.log();
|
|
115
|
+
|
|
116
|
+
console.log(colors.dim('Antigravity Workflows:'));
|
|
117
|
+
const workflows = [
|
|
118
|
+
'/component - Create WDS React component',
|
|
119
|
+
'/api-hook - Create React Query hook',
|
|
120
|
+
'/form - Create react-hook-form + zod form',
|
|
121
|
+
'/page - Create page component',
|
|
122
|
+
'/test - Create Vitest tests',
|
|
123
|
+
'/spring-api - Create Spring Boot API',
|
|
124
|
+
'/mybatis - Create MyBatis mapper',
|
|
125
|
+
'/django-view - Create Django DRF viewset',
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
for (const wf of workflows) {
|
|
129
|
+
console.log(` ${wf}`);
|
|
130
|
+
}
|
|
131
|
+
console.log();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Help command
|
|
136
|
+
*/
|
|
137
|
+
function help() {
|
|
138
|
+
console.log();
|
|
139
|
+
console.log(colors.blue('WooriDo Skills CLI'));
|
|
140
|
+
console.log();
|
|
141
|
+
console.log('Commands:');
|
|
142
|
+
console.log(' install Install skills to current directory');
|
|
143
|
+
console.log(' install --dry-run Show files without installing');
|
|
144
|
+
console.log(' list List available skills and workflows');
|
|
145
|
+
console.log(' help Show this help message');
|
|
146
|
+
console.log();
|
|
147
|
+
console.log('Examples:');
|
|
148
|
+
console.log(' npx woorido-skills install');
|
|
149
|
+
console.log(' npx woorido-skills list');
|
|
150
|
+
console.log();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Parse arguments
|
|
154
|
+
const args = process.argv.slice(2);
|
|
155
|
+
const command = args[0];
|
|
156
|
+
const flags = args.slice(1);
|
|
157
|
+
|
|
158
|
+
const options = {
|
|
159
|
+
dryRun: flags.includes('--dry-run'),
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Execute command
|
|
163
|
+
switch (command) {
|
|
164
|
+
case 'install':
|
|
165
|
+
install(options);
|
|
166
|
+
break;
|
|
167
|
+
case 'list':
|
|
168
|
+
list();
|
|
169
|
+
break;
|
|
170
|
+
case 'help':
|
|
171
|
+
case '--help':
|
|
172
|
+
case '-h':
|
|
173
|
+
help();
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
if (command) {
|
|
177
|
+
console.log(colors.red(`Unknown command: ${command}`));
|
|
178
|
+
}
|
|
179
|
+
help();
|
|
180
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@channeulparks/woorido-skills",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "WooriDo AI Coding Rules for Claude, Gemini, Antigravity and other AI coding assistants",
|
|
5
|
+
"main": "bin/cli.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"woorido-skills": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"templates"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "node bin/cli.js install --dry-run"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai",
|
|
18
|
+
"coding",
|
|
19
|
+
"rules",
|
|
20
|
+
"claude",
|
|
21
|
+
"gemini",
|
|
22
|
+
"antigravity",
|
|
23
|
+
"woorido",
|
|
24
|
+
"skills",
|
|
25
|
+
"react",
|
|
26
|
+
"spring-boot",
|
|
27
|
+
"django"
|
|
28
|
+
],
|
|
29
|
+
"author": "WooriDo Team",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/ParkChanNul/woorido-skills"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a React Query hook for API calls
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /api-hook [ResourceName]
|
|
6
|
+
|
|
7
|
+
<!-- React Query 기반 API 훅 생성 -->
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
```
|
|
11
|
+
/api-hook challenge
|
|
12
|
+
/api-hook user --mutations
|
|
13
|
+
/api-hook ledger --infinite
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
// turbo
|
|
19
|
+
1. Create `src/hooks/use[ResourceName].ts`:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
23
|
+
import { api } from '@/lib/api';
|
|
24
|
+
import type { [ResourceName] } from '@/types';
|
|
25
|
+
|
|
26
|
+
// Query Keys
|
|
27
|
+
export const [resourceName]Keys = {
|
|
28
|
+
all: ['[resourceName]s'] as const,
|
|
29
|
+
lists: () => [...[resourceName]Keys.all, 'list'] as const,
|
|
30
|
+
list: (filters: Record<string, unknown>) => [...[resourceName]Keys.lists(), filters] as const,
|
|
31
|
+
details: () => [...[resourceName]Keys.all, 'detail'] as const,
|
|
32
|
+
detail: (id: string) => [...[resourceName]Keys.details(), id] as const,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// GET single
|
|
36
|
+
export function use[ResourceName](id: string) {
|
|
37
|
+
return useQuery({
|
|
38
|
+
queryKey: [resourceName]Keys.detail(id),
|
|
39
|
+
queryFn: () => api.get<[ResourceName]>(`/[resourceName]s/${id}`),
|
|
40
|
+
enabled: !!id,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// GET list
|
|
45
|
+
export function use[ResourceName]List(filters?: Record<string, unknown>) {
|
|
46
|
+
return useQuery({
|
|
47
|
+
queryKey: [resourceName]Keys.list(filters ?? {}),
|
|
48
|
+
queryFn: () => api.get<[ResourceName][]>('/[resourceName]s', { params: filters }),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Mutations (--mutations flag)
|
|
54
|
+
|
|
55
|
+
<!-- 생성/수정/삭제 뮤테이션 추가 -->
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
// CREATE
|
|
59
|
+
export function useCreate[ResourceName]() {
|
|
60
|
+
const queryClient = useQueryClient();
|
|
61
|
+
|
|
62
|
+
return useMutation({
|
|
63
|
+
mutationFn: (data: Create[ResourceName]Request) =>
|
|
64
|
+
api.post<[ResourceName]>('/[resourceName]s', data),
|
|
65
|
+
onSuccess: () => {
|
|
66
|
+
queryClient.invalidateQueries({ queryKey: [resourceName]Keys.lists() });
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// UPDATE
|
|
72
|
+
export function useUpdate[ResourceName]() {
|
|
73
|
+
const queryClient = useQueryClient();
|
|
74
|
+
|
|
75
|
+
return useMutation({
|
|
76
|
+
mutationFn: ({ id, data }: { id: string; data: Update[ResourceName]Request }) =>
|
|
77
|
+
api.put<[ResourceName]>(`/[resourceName]s/${id}`, data),
|
|
78
|
+
onSuccess: (_, { id }) => {
|
|
79
|
+
queryClient.invalidateQueries({ queryKey: [resourceName]Keys.detail(id) });
|
|
80
|
+
queryClient.invalidateQueries({ queryKey: [resourceName]Keys.lists() });
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// DELETE
|
|
86
|
+
export function useDelete[ResourceName]() {
|
|
87
|
+
const queryClient = useQueryClient();
|
|
88
|
+
|
|
89
|
+
return useMutation({
|
|
90
|
+
mutationFn: (id: string) => api.delete(`/[resourceName]s/${id}`),
|
|
91
|
+
onSuccess: () => {
|
|
92
|
+
queryClient.invalidateQueries({ queryKey: [resourceName]Keys.lists() });
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Infinite Query (--infinite flag)
|
|
99
|
+
|
|
100
|
+
<!-- 무한 스크롤 목록 조회 -->
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { useInfiniteQuery } from '@tanstack/react-query';
|
|
104
|
+
|
|
105
|
+
export function use[ResourceName]Infinite(filters?: Record<string, unknown>) {
|
|
106
|
+
return useInfiniteQuery({
|
|
107
|
+
queryKey: [...[resourceName]Keys.lists(), 'infinite', filters],
|
|
108
|
+
queryFn: ({ pageParam = 0 }) =>
|
|
109
|
+
api.get<PaginatedResponse<[ResourceName]>>('/[resourceName]s', {
|
|
110
|
+
params: { ...filters, page: pageParam, size: 20 }
|
|
111
|
+
}),
|
|
112
|
+
getNextPageParam: (lastPage) =>
|
|
113
|
+
lastPage.hasNext ? lastPage.page + 1 : undefined,
|
|
114
|
+
initialPageParam: 0,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## API Client Reference
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// lib/api.ts
|
|
123
|
+
import axios from 'axios';
|
|
124
|
+
|
|
125
|
+
export const api = axios.create({
|
|
126
|
+
baseURL: import.meta.env.VITE_API_URL,
|
|
127
|
+
headers: { 'Content-Type': 'application/json' },
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
api.interceptors.response.use(
|
|
131
|
+
(res) => res.data,
|
|
132
|
+
(error) => Promise.reject(error.response?.data ?? error)
|
|
133
|
+
);
|
|
134
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a WDS-based React component with CSS Modules
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /component [ComponentName]
|
|
6
|
+
|
|
7
|
+
<!-- WDS 디자인 시스템 기반 React 컴포넌트 생성 -->
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
```
|
|
11
|
+
/component Button
|
|
12
|
+
/component Modal --radix
|
|
13
|
+
/component UserCard --domain
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
// turbo
|
|
19
|
+
1. Create folder `src/components/[ComponentName]/`
|
|
20
|
+
|
|
21
|
+
// turbo
|
|
22
|
+
2. Create `[ComponentName].tsx` with this template:
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import styles from './[ComponentName].module.css';
|
|
26
|
+
import clsx from 'clsx';
|
|
27
|
+
|
|
28
|
+
interface [ComponentName]Props {
|
|
29
|
+
className?: string;
|
|
30
|
+
children?: React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function [ComponentName]({ className, children }: [ComponentName]Props) {
|
|
34
|
+
return (
|
|
35
|
+
<div className={clsx(styles.root, className)}>
|
|
36
|
+
{children}
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
// turbo
|
|
43
|
+
3. Create `[ComponentName].module.css` with WDS tokens:
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
.root {
|
|
47
|
+
/* Layout */
|
|
48
|
+
display: flex;
|
|
49
|
+
|
|
50
|
+
/* Spacing - use WDS tokens */
|
|
51
|
+
padding: var(--space-4);
|
|
52
|
+
gap: var(--space-2);
|
|
53
|
+
|
|
54
|
+
/* Shape */
|
|
55
|
+
border-radius: var(--radius-md);
|
|
56
|
+
|
|
57
|
+
/* Colors */
|
|
58
|
+
background-color: var(--color-surface);
|
|
59
|
+
color: var(--color-text-primary);
|
|
60
|
+
|
|
61
|
+
/* Shadow */
|
|
62
|
+
box-shadow: var(--shadow-sm);
|
|
63
|
+
|
|
64
|
+
/* Motion */
|
|
65
|
+
transition: box-shadow var(--motion-duration-fast) var(--motion-ease-standard);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.root:hover {
|
|
69
|
+
box-shadow: var(--shadow-md);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
// turbo
|
|
74
|
+
4. Create `index.ts` for re-export:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
export { [ComponentName] } from './[ComponentName]';
|
|
78
|
+
export type { [ComponentName]Props } from './[ComponentName]';
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Radix UI Wrapping (--radix flag)
|
|
82
|
+
|
|
83
|
+
<!-- Radix UI 컴포넌트 래핑 시 적용 -->
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import * as Dialog from '@radix-ui/react-dialog';
|
|
87
|
+
import styles from './Modal.module.css';
|
|
88
|
+
|
|
89
|
+
export function Modal({ open, onOpenChange, children }) {
|
|
90
|
+
return (
|
|
91
|
+
<Dialog.Root open={open} onOpenChange={onOpenChange}>
|
|
92
|
+
<Dialog.Portal>
|
|
93
|
+
<Dialog.Overlay className={styles.overlay} />
|
|
94
|
+
<Dialog.Content className={styles.content}>
|
|
95
|
+
{children}
|
|
96
|
+
</Dialog.Content>
|
|
97
|
+
</Dialog.Portal>
|
|
98
|
+
</Dialog.Root>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Domain Component (--domain flag)
|
|
104
|
+
|
|
105
|
+
<!-- 도메인 특화 컴포넌트 (BrixBadge, FinancialText 등) -->
|
|
106
|
+
|
|
107
|
+
Place in `src/components/domain/` folder.
|
|
108
|
+
|
|
109
|
+
## WDS Token Reference
|
|
110
|
+
|
|
111
|
+
| Category | Tokens |
|
|
112
|
+
|----------|--------|
|
|
113
|
+
| Colors | `--color-orange-*`, `--color-grey-*` |
|
|
114
|
+
| Spacing | `--space-1` ~ `--space-12` |
|
|
115
|
+
| Radius | `--radius-sm/md/lg/xl/full` |
|
|
116
|
+
| Shadow | `--shadow-sm/md/lg/xl` |
|
|
117
|
+
| Motion | `--motion-duration-*`, `--motion-ease-*` |
|