@kood/claude-code 0.2.0 → 0.2.2
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/dist/index.js +62 -18
- package/package.json +1 -1
- package/templates/.claude/agents/code-reviewer.md +31 -0
- package/templates/.claude/agents/debug-detective.md +37 -0
- package/templates/.claude/agents/refactor-advisor.md +44 -0
- package/templates/.claude/agents/test-writer.md +41 -0
- package/templates/.claude/skills/frontend-design/SKILL.md +310 -0
- package/templates/.claude/skills/frontend-design/references/animation-patterns.md +446 -0
- package/templates/.claude/skills/frontend-design/references/colors-2026.md +244 -0
- package/templates/.claude/skills/frontend-design/references/typography-2026.md +302 -0
- package/templates/.claude/skills/gemini-review/SKILL.md +1 -1
- package/templates/hono/docs/library/drizzle/cloudflare-d1.md +247 -0
- package/templates/hono/docs/library/drizzle/config.md +167 -0
- package/templates/hono/docs/library/drizzle/index.md +259 -0
- package/templates/tanstack-start/docs/library/drizzle/cloudflare-d1.md +146 -0
- package/templates/tanstack-start/docs/library/drizzle/config.md +118 -0
- package/templates/tanstack-start/docs/library/drizzle/crud.md +205 -0
- package/templates/tanstack-start/docs/library/drizzle/index.md +79 -0
- package/templates/tanstack-start/docs/library/drizzle/relations.md +202 -0
- package/templates/tanstack-start/docs/library/drizzle/schema.md +154 -0
- package/templates/tanstack-start/docs/library/drizzle/setup.md +95 -0
- package/templates/tanstack-start/docs/library/drizzle/transactions.md +127 -0
- package/templates/tanstack-start/docs/library/tanstack-router/error-handling.md +204 -0
- package/templates/tanstack-start/docs/library/tanstack-router/hooks.md +195 -0
- package/templates/tanstack-start/docs/library/tanstack-router/index.md +150 -0
- package/templates/tanstack-start/docs/library/tanstack-router/navigation.md +150 -0
- package/templates/tanstack-start/docs/library/tanstack-router/route-context.md +203 -0
- package/templates/tanstack-start/docs/library/tanstack-router/search-params.md +213 -0
package/dist/index.js
CHANGED
|
@@ -159,26 +159,42 @@ var copyCommands = async (_templates, targetDir) => {
|
|
|
159
159
|
}
|
|
160
160
|
return counter;
|
|
161
161
|
};
|
|
162
|
-
var checkSkillsAndCommandsExist = async (_templates) => {
|
|
163
|
-
const claudeDir = path.join(getTemplatesDir(), ".claude");
|
|
164
|
-
const skillsSrc = path.join(claudeDir, "skills");
|
|
165
|
-
const commandsSrc = path.join(claudeDir, "commands");
|
|
166
|
-
const hasSkills = await fs.pathExists(skillsSrc);
|
|
167
|
-
const hasCommands = await fs.pathExists(commandsSrc);
|
|
168
|
-
return { hasSkills, hasCommands };
|
|
169
|
-
};
|
|
170
162
|
var checkExistingClaudeFiles = async (targetDir) => {
|
|
171
163
|
const existingFiles = [];
|
|
172
164
|
const skillsDir = path.join(targetDir, ".claude", "skills");
|
|
173
165
|
const commandsDir = path.join(targetDir, ".claude", "commands");
|
|
166
|
+
const agentsDir = path.join(targetDir, ".claude", "agents");
|
|
174
167
|
if (await fs.pathExists(skillsDir)) {
|
|
175
168
|
existingFiles.push(".claude/skills/");
|
|
176
169
|
}
|
|
177
170
|
if (await fs.pathExists(commandsDir)) {
|
|
178
171
|
existingFiles.push(".claude/commands/");
|
|
179
172
|
}
|
|
173
|
+
if (await fs.pathExists(agentsDir)) {
|
|
174
|
+
existingFiles.push(".claude/agents/");
|
|
175
|
+
}
|
|
180
176
|
return existingFiles;
|
|
181
177
|
};
|
|
178
|
+
var copyAgents = async (_templates, targetDir) => {
|
|
179
|
+
const counter = { files: 0, directories: 0 };
|
|
180
|
+
const targetAgentsDir = path.join(targetDir, ".claude", "agents");
|
|
181
|
+
const agentsSrc = path.join(getTemplatesDir(), ".claude", "agents");
|
|
182
|
+
if (await fs.pathExists(agentsSrc)) {
|
|
183
|
+
await fs.ensureDir(targetAgentsDir);
|
|
184
|
+
await copyRecursive(agentsSrc, targetAgentsDir, counter);
|
|
185
|
+
}
|
|
186
|
+
return counter;
|
|
187
|
+
};
|
|
188
|
+
var checkAllExtrasExist = async (_templates) => {
|
|
189
|
+
const claudeDir = path.join(getTemplatesDir(), ".claude");
|
|
190
|
+
const skillsSrc = path.join(claudeDir, "skills");
|
|
191
|
+
const commandsSrc = path.join(claudeDir, "commands");
|
|
192
|
+
const agentsSrc = path.join(claudeDir, "agents");
|
|
193
|
+
const hasSkills = await fs.pathExists(skillsSrc);
|
|
194
|
+
const hasCommands = await fs.pathExists(commandsSrc);
|
|
195
|
+
const hasAgents = await fs.pathExists(agentsSrc);
|
|
196
|
+
return { hasSkills, hasCommands, hasAgents };
|
|
197
|
+
};
|
|
182
198
|
|
|
183
199
|
// src/commands/init.ts
|
|
184
200
|
var TEMPLATE_DESCRIPTIONS = {
|
|
@@ -270,17 +286,19 @@ var init = async (options) => {
|
|
|
270
286
|
}
|
|
271
287
|
logger.blank();
|
|
272
288
|
logger.success(`Total: ${totalFiles} files, ${totalDirectories} directories`);
|
|
273
|
-
const { hasSkills, hasCommands } = await
|
|
289
|
+
const { hasSkills, hasCommands, hasAgents } = await checkAllExtrasExist(templates);
|
|
274
290
|
let installSkills = options.skills ?? false;
|
|
275
291
|
let installCommands = options.commands ?? false;
|
|
276
|
-
|
|
292
|
+
let installAgents = options.agents ?? false;
|
|
293
|
+
const noOptionsProvided = options.skills === void 0 && options.commands === void 0 && options.agents === void 0;
|
|
294
|
+
if (noOptionsProvided && (hasSkills || hasCommands || hasAgents)) {
|
|
277
295
|
logger.blank();
|
|
278
296
|
if (hasSkills) {
|
|
279
297
|
const skillsResponse = await prompts({
|
|
280
298
|
type: "confirm",
|
|
281
299
|
name: "install",
|
|
282
300
|
message: "Install skills to .claude/skills/?",
|
|
283
|
-
initial:
|
|
301
|
+
initial: false
|
|
284
302
|
});
|
|
285
303
|
installSkills = skillsResponse.install ?? false;
|
|
286
304
|
}
|
|
@@ -289,12 +307,21 @@ var init = async (options) => {
|
|
|
289
307
|
type: "confirm",
|
|
290
308
|
name: "install",
|
|
291
309
|
message: "Install commands to .claude/commands/?",
|
|
292
|
-
initial:
|
|
310
|
+
initial: false
|
|
293
311
|
});
|
|
294
312
|
installCommands = commandsResponse.install ?? false;
|
|
295
313
|
}
|
|
314
|
+
if (hasAgents) {
|
|
315
|
+
const agentsResponse = await prompts({
|
|
316
|
+
type: "confirm",
|
|
317
|
+
name: "install",
|
|
318
|
+
message: "Install agents to .claude/agents/?",
|
|
319
|
+
initial: false
|
|
320
|
+
});
|
|
321
|
+
installAgents = agentsResponse.install ?? false;
|
|
322
|
+
}
|
|
296
323
|
}
|
|
297
|
-
if (installSkills || installCommands) {
|
|
324
|
+
if (installSkills || installCommands || installAgents) {
|
|
298
325
|
const existingClaudeFiles = await checkExistingClaudeFiles(targetDir);
|
|
299
326
|
if (existingClaudeFiles.length > 0 && !options.force) {
|
|
300
327
|
logger.warn("The following .claude files/folders already exist:");
|
|
@@ -307,9 +334,10 @@ var init = async (options) => {
|
|
|
307
334
|
initial: false
|
|
308
335
|
});
|
|
309
336
|
if (!response.overwrite) {
|
|
310
|
-
logger.info("Skipping
|
|
337
|
+
logger.info("Skipping extras installation.");
|
|
311
338
|
installSkills = false;
|
|
312
339
|
installCommands = false;
|
|
340
|
+
installAgents = false;
|
|
313
341
|
}
|
|
314
342
|
}
|
|
315
343
|
if (installSkills && hasSkills) {
|
|
@@ -336,13 +364,25 @@ var init = async (options) => {
|
|
|
336
364
|
} else if (installCommands && !hasCommands) {
|
|
337
365
|
logger.warn("No commands found in selected templates.");
|
|
338
366
|
}
|
|
367
|
+
if (installAgents && hasAgents) {
|
|
368
|
+
logger.blank();
|
|
369
|
+
logger.info("Installing agents...");
|
|
370
|
+
const agentsResult = await copyAgents(templates, targetDir);
|
|
371
|
+
totalFiles += agentsResult.files;
|
|
372
|
+
totalDirectories += agentsResult.directories;
|
|
373
|
+
logger.success(
|
|
374
|
+
`Agents: ${agentsResult.files} files, ${agentsResult.directories} directories`
|
|
375
|
+
);
|
|
376
|
+
} else if (installAgents && !hasAgents) {
|
|
377
|
+
logger.warn("No agents found in selected templates.");
|
|
378
|
+
}
|
|
339
379
|
}
|
|
340
380
|
logger.blank();
|
|
341
381
|
logger.success("Claude Code documentation installed!");
|
|
342
382
|
logger.blank();
|
|
343
383
|
logger.info("Installed templates:");
|
|
344
384
|
templates.forEach((t) => logger.step(t));
|
|
345
|
-
if (installSkills || installCommands) {
|
|
385
|
+
if (installSkills || installCommands || installAgents) {
|
|
346
386
|
logger.blank();
|
|
347
387
|
logger.info("Installed extras:");
|
|
348
388
|
if (installSkills) {
|
|
@@ -351,6 +391,9 @@ var init = async (options) => {
|
|
|
351
391
|
if (installCommands) {
|
|
352
392
|
logger.step("Commands \u2192 .claude/commands/");
|
|
353
393
|
}
|
|
394
|
+
if (installAgents) {
|
|
395
|
+
logger.step("Agents \u2192 .claude/agents/");
|
|
396
|
+
}
|
|
354
397
|
}
|
|
355
398
|
logger.blank();
|
|
356
399
|
logger.info("Next steps:");
|
|
@@ -361,11 +404,11 @@ var init = async (options) => {
|
|
|
361
404
|
|
|
362
405
|
// src/index.ts
|
|
363
406
|
var program = new Command();
|
|
364
|
-
program.name("claude-code").description("Claude Code documentation installer for projects").version("0.2.
|
|
407
|
+
program.name("claude-code").description("Claude Code documentation installer for projects").version("0.2.2");
|
|
365
408
|
program.option(
|
|
366
409
|
"-t, --template <names>",
|
|
367
410
|
"template names (comma-separated: tanstack-start,hono)"
|
|
368
|
-
).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").option("-s, --skills", "install skills to .claude/skills/").option("-c, --commands", "install commands to .claude/commands/").action(async (options) => {
|
|
411
|
+
).option("-f, --force", "overwrite existing files without prompting").option("--cwd <path>", "target directory (default: current directory)").option("--list", "list available templates").option("-s, --skills", "install skills to .claude/skills/").option("-c, --commands", "install commands to .claude/commands/").option("-a, --agents", "install agents to .claude/agents/").action(async (options) => {
|
|
369
412
|
banner();
|
|
370
413
|
if (options.list) {
|
|
371
414
|
const templates = await listAvailableTemplates();
|
|
@@ -379,7 +422,8 @@ program.option(
|
|
|
379
422
|
force: options.force,
|
|
380
423
|
cwd: options.cwd,
|
|
381
424
|
skills: options.skills,
|
|
382
|
-
commands: options.commands
|
|
425
|
+
commands: options.commands,
|
|
426
|
+
agents: options.agents
|
|
383
427
|
});
|
|
384
428
|
});
|
|
385
429
|
program.parse();
|
package/package.json
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-reviewer
|
|
3
|
+
description: 코드 리뷰. git diff 분석, 버그/보안/품질 이슈 탐지. "리뷰해줘", "코드 봐줘" 요청 시 사용.
|
|
4
|
+
model: inherit
|
|
5
|
+
color: red
|
|
6
|
+
tools: ["Read", "Grep", "Bash"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are an expert code reviewer.
|
|
10
|
+
|
|
11
|
+
## Responsibilities
|
|
12
|
+
|
|
13
|
+
1. 버그 탐지 - 로직 오류, null/undefined, 레이스 컨디션
|
|
14
|
+
2. 보안 검토 - 인젝션, XSS, 민감 데이터 노출
|
|
15
|
+
3. 품질 확인 - 중복, 에러 핸들링, CLAUDE.md 규칙 준수
|
|
16
|
+
|
|
17
|
+
## Process
|
|
18
|
+
|
|
19
|
+
1. `git diff` 또는 지정 파일 분석
|
|
20
|
+
2. 이슈 심각도 분류 (Critical/Important)
|
|
21
|
+
3. 구체적 수정안 제시
|
|
22
|
+
|
|
23
|
+
## Confidence
|
|
24
|
+
|
|
25
|
+
80점 이상만 보고:
|
|
26
|
+
- 75+ : 확실한 이슈
|
|
27
|
+
- 100 : 반드시 수정
|
|
28
|
+
|
|
29
|
+
## Output
|
|
30
|
+
|
|
31
|
+
Critical → Important 순으로 `[파일:라인]` + 이슈 + 수정안 제시.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debug-detective
|
|
3
|
+
description: 디버깅 전문가. 버그 원인 분석 및 수정안 제시. "에러", "버그", "안돼" 요청 시 사용.
|
|
4
|
+
model: inherit
|
|
5
|
+
color: yellow
|
|
6
|
+
tools: ["Read", "Grep", "Glob", "Bash"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are a debugging specialist.
|
|
10
|
+
|
|
11
|
+
## Responsibilities
|
|
12
|
+
|
|
13
|
+
1. 에러 분석 - 스택 트레이스, 로그, 재현 조건
|
|
14
|
+
2. 원인 추적 - 코드 흐름 따라 근본 원인 탐지
|
|
15
|
+
3. 수정안 제시 - 최소 변경으로 해결
|
|
16
|
+
|
|
17
|
+
## Process
|
|
18
|
+
|
|
19
|
+
1. 증상 파악 (에러 메시지, 재현 단계)
|
|
20
|
+
2. 가설 수립 (가능한 원인 목록)
|
|
21
|
+
3. 코드 분석으로 가설 검증
|
|
22
|
+
4. 근본 원인 수정
|
|
23
|
+
|
|
24
|
+
## Common Patterns
|
|
25
|
+
|
|
26
|
+
| 패턴 | 증상 | 확인 |
|
|
27
|
+
|------|------|------|
|
|
28
|
+
| Null Reference | TypeError | 옵셔널 체이닝 |
|
|
29
|
+
| Race Condition | 간헐적 실패 | async/await |
|
|
30
|
+
| Off-by-One | 잘못된 인덱스 | 반복문 경계 |
|
|
31
|
+
| State Mutation | 예상외 변경 | 불변성 |
|
|
32
|
+
|
|
33
|
+
## Rules
|
|
34
|
+
|
|
35
|
+
- 추측 금지, 코드 근거 필수
|
|
36
|
+
- 최소 변경 원칙
|
|
37
|
+
- Before/After 코드 제시
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: refactor-advisor
|
|
3
|
+
description: 리팩토링 조언. 코드 개선점 분석 및 계획 수립. "리팩토링", "정리", "개선" 요청 시 사용.
|
|
4
|
+
model: inherit
|
|
5
|
+
color: cyan
|
|
6
|
+
tools: ["Read", "Grep", "Glob"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are a refactoring specialist.
|
|
10
|
+
|
|
11
|
+
## Responsibilities
|
|
12
|
+
|
|
13
|
+
1. 코드 스멜 탐지 - 중복, 긴 함수, 복잡한 조건문
|
|
14
|
+
2. 구조 개선 - 모듈화, 관심사 분리
|
|
15
|
+
3. 안전한 계획 - 단계별 실행, 테스트 보장
|
|
16
|
+
|
|
17
|
+
## Process
|
|
18
|
+
|
|
19
|
+
1. 현재 코드 구조 파악
|
|
20
|
+
2. 문제점/개선점 식별
|
|
21
|
+
3. 우선순위 결정
|
|
22
|
+
4. 단계별 계획 수립
|
|
23
|
+
|
|
24
|
+
## Code Smells
|
|
25
|
+
|
|
26
|
+
| 카테고리 | 예시 |
|
|
27
|
+
|----------|------|
|
|
28
|
+
| Bloaters | 긴 메서드, 큰 클래스 |
|
|
29
|
+
| Couplers | 과도한 의존성 |
|
|
30
|
+
| Dispensables | 중복, 죽은 코드 |
|
|
31
|
+
|
|
32
|
+
## Techniques
|
|
33
|
+
|
|
34
|
+
| 기법 | 상황 |
|
|
35
|
+
|------|------|
|
|
36
|
+
| Extract Function | 긴 함수, 중복 |
|
|
37
|
+
| Extract Component | 복잡한 UI |
|
|
38
|
+
| Replace Conditional | 복잡한 if/switch |
|
|
39
|
+
|
|
40
|
+
## Rules
|
|
41
|
+
|
|
42
|
+
- 한 번에 하나의 리팩토링
|
|
43
|
+
- 각 단계 후 테스트
|
|
44
|
+
- 기능 변경 없이 구조만 개선
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-writer
|
|
3
|
+
description: 테스트 작성. 함수/컴포넌트 테스트 생성. "테스트 추가", "테스트 작성" 요청 시 사용.
|
|
4
|
+
model: inherit
|
|
5
|
+
color: green
|
|
6
|
+
tools: ["Read", "Write", "Grep", "Glob"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are a testing specialist.
|
|
10
|
+
|
|
11
|
+
## Responsibilities
|
|
12
|
+
|
|
13
|
+
1. 유닛 테스트 - 함수, 클래스 단위
|
|
14
|
+
2. 통합 테스트 - API, 서비스 상호작용
|
|
15
|
+
3. 엣지 케이스 - 경계값, 에러, 빈 입력
|
|
16
|
+
|
|
17
|
+
## Process
|
|
18
|
+
|
|
19
|
+
1. 대상 코드 분석 (입력/출력, 의존성)
|
|
20
|
+
2. 테스트 케이스 도출 (정상, 엣지, 에러)
|
|
21
|
+
3. 프로젝트 테스트 패턴 확인
|
|
22
|
+
4. 테스트 코드 작성
|
|
23
|
+
|
|
24
|
+
## Coverage Priority
|
|
25
|
+
|
|
26
|
+
| 우선순위 | 케이스 |
|
|
27
|
+
|----------|--------|
|
|
28
|
+
| 필수 | happy path |
|
|
29
|
+
| 필수 | 에러 핸들링 |
|
|
30
|
+
| 권장 | 경계값 |
|
|
31
|
+
| 권장 | null/undefined |
|
|
32
|
+
|
|
33
|
+
## Structure
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
describe('[대상]', () => {
|
|
37
|
+
it('should [동작] when [조건]', () => {
|
|
38
|
+
// Arrange → Act → Assert
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
```
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: 프론트엔드 UI 구현 스킬. 컴포넌트, 페이지, 애플리케이션 구축 시 사용. 2026 트렌드 기반 고품질 디자인 생성.
|
|
4
|
+
license: Complete terms in LICENSE.txt
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Frontend Design Skill
|
|
8
|
+
|
|
9
|
+
프로덕션급 프론트엔드 인터페이스 구현. 독창적이고 기억에 남는 디자인.
|
|
10
|
+
|
|
11
|
+
## 사용 시점
|
|
12
|
+
|
|
13
|
+
| 트리거 | 예시 |
|
|
14
|
+
|--------|------|
|
|
15
|
+
| UI 컴포넌트 요청 | "버튼 컴포넌트 만들어줘" |
|
|
16
|
+
| 페이지 구현 | "랜딩 페이지 만들어줘" |
|
|
17
|
+
| 스타일링 작업 | "다크 테마 적용해줘" |
|
|
18
|
+
| 애니메이션 추가 | "hover 효과 넣어줘" |
|
|
19
|
+
|
|
20
|
+
## 디자인 프로세스
|
|
21
|
+
|
|
22
|
+
### 1단계: 컨텍스트 파악
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
- 목적: 무슨 문제 해결?
|
|
26
|
+
- 대상: 누가 사용?
|
|
27
|
+
- 제약: 프레임워크, 성능, 접근성 요구사항
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2단계: 미적 방향 결정
|
|
31
|
+
|
|
32
|
+
**반드시 하나 선택하고 일관성 유지:**
|
|
33
|
+
|
|
34
|
+
| 방향 | 특징 | 적합한 상황 |
|
|
35
|
+
|------|------|-------------|
|
|
36
|
+
| Liquid Glass | 투명도, 깊이, 유동적 표면 | 모던 앱, 대시보드 |
|
|
37
|
+
| Calm Minimal | 여백, 선명한 타이포, 절제 | 콘텐츠 중심, 포트폴리오 |
|
|
38
|
+
| Bold Maximalist | 큰 타이포, 강렬한 색, 레이어 | 크리에이티브, 브랜드 |
|
|
39
|
+
| Organic Natural | 부드러운 곡선, 어시 톤, 텍스처 | 웰빙, 라이프스타일 |
|
|
40
|
+
| Editorial | 매거진 레이아웃, 그리드 플레이 | 미디어, 블로그 |
|
|
41
|
+
| Retro Futuristic | 네온, 그라디언트, 글리치 | 테크, 게임 |
|
|
42
|
+
|
|
43
|
+
### 3단계: 구현
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
1. CSS 변수로 디자인 토큰 정의
|
|
47
|
+
2. 타이포그래피 시스템 설정
|
|
48
|
+
3. 컬러 팔레트 적용
|
|
49
|
+
4. 레이아웃 구조화
|
|
50
|
+
5. 애니메이션/인터랙션 추가
|
|
51
|
+
6. 접근성 검증
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 핵심 규칙
|
|
55
|
+
|
|
56
|
+
### 타이포그래피
|
|
57
|
+
|
|
58
|
+
**DO:**
|
|
59
|
+
```css
|
|
60
|
+
/* Variable fonts 사용 */
|
|
61
|
+
@font-face {
|
|
62
|
+
font-family: 'Display';
|
|
63
|
+
src: url('font.woff2') format('woff2');
|
|
64
|
+
font-weight: 100 900;
|
|
65
|
+
font-display: swap;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* 명확한 위계 */
|
|
69
|
+
--font-display: 'Playfair Display', serif; /* 헤드라인 */
|
|
70
|
+
--font-body: 'Source Sans 3', sans-serif; /* 본문 */
|
|
71
|
+
--font-mono: 'JetBrains Mono', monospace; /* 코드 */
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**DON'T:**
|
|
75
|
+
```css
|
|
76
|
+
/* ❌ 금지 - 일반적인 시스템 폰트 */
|
|
77
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
78
|
+
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
|
|
79
|
+
|
|
80
|
+
/* ❌ 금지 - AI 슬롭 폰트 */
|
|
81
|
+
font-family: 'Inter', sans-serif;
|
|
82
|
+
font-family: 'Roboto', sans-serif;
|
|
83
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**추천 폰트 페어링:**
|
|
87
|
+
|
|
88
|
+
| 헤드라인 | 본문 | 무드 |
|
|
89
|
+
|----------|------|------|
|
|
90
|
+
| Playfair Display | Source Sans 3 | 클래식, 에디토리얼 |
|
|
91
|
+
| Clash Display | Satoshi | 모던, 볼드 |
|
|
92
|
+
| Fraunces | Work Sans | 따뜻한, 친근한 |
|
|
93
|
+
| Space Mono | DM Sans | 테크, 미니멀 |
|
|
94
|
+
| Syne | Inter (예외적 허용) | 크리에이티브 |
|
|
95
|
+
|
|
96
|
+
**상세**: [references/typography-2026.md](references/typography-2026.md)
|
|
97
|
+
|
|
98
|
+
### 컬러
|
|
99
|
+
|
|
100
|
+
**DO:**
|
|
101
|
+
```css
|
|
102
|
+
/* OKLCH 컬러 시스템 (2026 표준) */
|
|
103
|
+
:root {
|
|
104
|
+
/* 베이스 - 소프트 뉴트럴 (순백색 X) */
|
|
105
|
+
--bg-primary: oklch(98% 0.005 90); /* 웜 오프화이트 */
|
|
106
|
+
--bg-secondary: oklch(95% 0.01 90); /* 린넨 */
|
|
107
|
+
|
|
108
|
+
/* 텍스트 */
|
|
109
|
+
--text-primary: oklch(20% 0.01 90); /* 소프트 블랙 */
|
|
110
|
+
--text-secondary: oklch(45% 0.02 90); /* 뮤트 그레이 */
|
|
111
|
+
|
|
112
|
+
/* 액센트 - 하나만 강하게 */
|
|
113
|
+
--accent: oklch(65% 0.25 180); /* Transformative Teal */
|
|
114
|
+
--accent-hover: oklch(60% 0.28 180);
|
|
115
|
+
|
|
116
|
+
/* 상태 */
|
|
117
|
+
--success: oklch(70% 0.2 145);
|
|
118
|
+
--error: oklch(65% 0.25 25);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* 다크 모드 */
|
|
122
|
+
@media (prefers-color-scheme: dark) {
|
|
123
|
+
:root {
|
|
124
|
+
--bg-primary: oklch(15% 0.01 90);
|
|
125
|
+
--bg-secondary: oklch(20% 0.015 90);
|
|
126
|
+
--text-primary: oklch(90% 0.01 90);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**DON'T:**
|
|
132
|
+
```css
|
|
133
|
+
/* ❌ 금지 - 순백색 배경 */
|
|
134
|
+
background: #ffffff;
|
|
135
|
+
background: white;
|
|
136
|
+
|
|
137
|
+
/* ❌ 금지 - AI 슬롭 퍼플 그라디언트 */
|
|
138
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
139
|
+
background: linear-gradient(to right, #8b5cf6, #a855f7);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**2026 트렌드 컬러:**
|
|
143
|
+
|
|
144
|
+
| 이름 | OKLCH | HEX (참고) | 용도 |
|
|
145
|
+
|------|-------|-----------|------|
|
|
146
|
+
| Cloud Dancer | oklch(97% 0.005 90) | #F5F5F5 | 배경, 여백 |
|
|
147
|
+
| Mocha Mousse | oklch(55% 0.08 55) | #A47764 | 어시, 따뜻함 |
|
|
148
|
+
| Transformative Teal | oklch(65% 0.15 180) | #2D9CCA | 액센트 |
|
|
149
|
+
| Neo Mint | oklch(85% 0.1 160) | #AAF0D1 | 프레시, 테크 |
|
|
150
|
+
| Soft Coral | oklch(75% 0.12 30) | #FFB5A7 | 따뜻한 액센트 |
|
|
151
|
+
|
|
152
|
+
**상세**: [references/colors-2026.md](references/colors-2026.md)
|
|
153
|
+
|
|
154
|
+
### 애니메이션
|
|
155
|
+
|
|
156
|
+
**원칙:**
|
|
157
|
+
1. **목적 있는 움직임만** - 장식적 애니메이션 금지
|
|
158
|
+
2. **300ms 이하** - 트랜지션은 빠르게
|
|
159
|
+
3. **GPU 가속** - transform, opacity만 애니메이트
|
|
160
|
+
4. **접근성** - prefers-reduced-motion 존중
|
|
161
|
+
|
|
162
|
+
**DO:**
|
|
163
|
+
```css
|
|
164
|
+
/* 기본 트랜지션 */
|
|
165
|
+
.button {
|
|
166
|
+
transition: transform 200ms ease-out,
|
|
167
|
+
background-color 150ms ease;
|
|
168
|
+
}
|
|
169
|
+
.button:hover {
|
|
170
|
+
transform: translateY(-2px);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* 스태거 애니메이션 */
|
|
174
|
+
.list-item {
|
|
175
|
+
animation: fadeInUp 400ms ease-out backwards;
|
|
176
|
+
}
|
|
177
|
+
.list-item:nth-child(1) { animation-delay: 0ms; }
|
|
178
|
+
.list-item:nth-child(2) { animation-delay: 50ms; }
|
|
179
|
+
.list-item:nth-child(3) { animation-delay: 100ms; }
|
|
180
|
+
|
|
181
|
+
@keyframes fadeInUp {
|
|
182
|
+
from {
|
|
183
|
+
opacity: 0;
|
|
184
|
+
transform: translateY(20px);
|
|
185
|
+
}
|
|
186
|
+
to {
|
|
187
|
+
opacity: 1;
|
|
188
|
+
transform: translateY(0);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* 접근성 */
|
|
193
|
+
@media (prefers-reduced-motion: reduce) {
|
|
194
|
+
*, *::before, *::after {
|
|
195
|
+
animation-duration: 0.01ms !important;
|
|
196
|
+
transition-duration: 0.01ms !important;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**DON'T:**
|
|
202
|
+
```css
|
|
203
|
+
/* ❌ 금지 - 레이아웃 속성 애니메이트 */
|
|
204
|
+
transition: width 300ms, height 300ms, margin 300ms;
|
|
205
|
+
|
|
206
|
+
/* ❌ 금지 - 너무 느린 트랜지션 */
|
|
207
|
+
transition: all 1s ease;
|
|
208
|
+
|
|
209
|
+
/* ❌ 금지 - 무한 회전 (목적 없는 장식) */
|
|
210
|
+
animation: spin 2s infinite linear;
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**React (Motion 라이브러리):**
|
|
214
|
+
```tsx
|
|
215
|
+
import { motion } from 'motion/react';
|
|
216
|
+
|
|
217
|
+
// 페이지 진입
|
|
218
|
+
<motion.div
|
|
219
|
+
initial={{ opacity: 0, y: 20 }}
|
|
220
|
+
animate={{ opacity: 1, y: 0 }}
|
|
221
|
+
transition={{ duration: 0.3, ease: 'easeOut' }}
|
|
222
|
+
>
|
|
223
|
+
{content}
|
|
224
|
+
</motion.div>
|
|
225
|
+
|
|
226
|
+
// 리스트 스태거
|
|
227
|
+
<motion.ul>
|
|
228
|
+
{items.map((item, i) => (
|
|
229
|
+
<motion.li
|
|
230
|
+
key={item.id}
|
|
231
|
+
initial={{ opacity: 0, x: -20 }}
|
|
232
|
+
animate={{ opacity: 1, x: 0 }}
|
|
233
|
+
transition={{ delay: i * 0.05 }}
|
|
234
|
+
>
|
|
235
|
+
{item.name}
|
|
236
|
+
</motion.li>
|
|
237
|
+
))}
|
|
238
|
+
</motion.ul>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**상세**: [references/animation-patterns.md](references/animation-patterns.md)
|
|
242
|
+
|
|
243
|
+
### 레이아웃
|
|
244
|
+
|
|
245
|
+
**DO:**
|
|
246
|
+
```css
|
|
247
|
+
/* 비대칭, 그리드 브레이킹 */
|
|
248
|
+
.hero {
|
|
249
|
+
display: grid;
|
|
250
|
+
grid-template-columns: 1fr 1.5fr;
|
|
251
|
+
gap: clamp(2rem, 5vw, 4rem);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* 여백은 넉넉하게 */
|
|
255
|
+
section {
|
|
256
|
+
padding: clamp(4rem, 10vh, 8rem) 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* Container queries (2026 표준) */
|
|
260
|
+
@container (min-width: 400px) {
|
|
261
|
+
.card { flex-direction: row; }
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**DON'T:**
|
|
266
|
+
```css
|
|
267
|
+
/* ❌ 금지 - 완벽한 대칭 (지루함) */
|
|
268
|
+
grid-template-columns: 1fr 1fr;
|
|
269
|
+
|
|
270
|
+
/* ❌ 금지 - 빽빽한 레이아웃 */
|
|
271
|
+
padding: 10px;
|
|
272
|
+
gap: 8px;
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## 접근성 체크리스트
|
|
276
|
+
|
|
277
|
+
| 항목 | 기준 | 확인 |
|
|
278
|
+
|------|------|------|
|
|
279
|
+
| 색상 대비 | WCAG AA (4.5:1 텍스트, 3:1 UI) | [ ] |
|
|
280
|
+
| 키보드 네비게이션 | 모든 인터랙티브 요소 접근 가능 | [ ] |
|
|
281
|
+
| 포커스 표시 | 명확한 포커스 링 | [ ] |
|
|
282
|
+
| 모션 감소 | prefers-reduced-motion 처리 | [ ] |
|
|
283
|
+
| 스크린 리더 | 시맨틱 HTML, aria-label | [ ] |
|
|
284
|
+
| 텍스트 크기 | 16px 이상 본문 | [ ] |
|
|
285
|
+
| 터치 타겟 | 44x44px 이상 | [ ] |
|
|
286
|
+
|
|
287
|
+
## 금지 사항 (Anti-patterns)
|
|
288
|
+
|
|
289
|
+
| 카테고리 | 금지 항목 |
|
|
290
|
+
|----------|----------|
|
|
291
|
+
| 폰트 | Inter, Roboto, Arial, system fonts 단독 사용 |
|
|
292
|
+
| 컬러 | 퍼플 그라디언트 on 화이트, 순백색 배경 |
|
|
293
|
+
| 레이아웃 | 완벽 대칭, 좁은 여백, 쿠키커터 카드 |
|
|
294
|
+
| 애니메이션 | 목적 없는 회전, 1초+ 트랜지션, layout 애니메이트 |
|
|
295
|
+
| 패턴 | 동일한 그림자, 동일한 border-radius, 복사된 UI |
|
|
296
|
+
|
|
297
|
+
## 참조 문서
|
|
298
|
+
|
|
299
|
+
- [references/typography-2026.md](references/typography-2026.md) - 폰트 선택, 스케일, 페어링
|
|
300
|
+
- [references/colors-2026.md](references/colors-2026.md) - OKLCH, 팔레트, 다크모드
|
|
301
|
+
- [references/animation-patterns.md](references/animation-patterns.md) - CSS/JS 패턴, 라이브러리
|
|
302
|
+
|
|
303
|
+
## Sources
|
|
304
|
+
|
|
305
|
+
- [UI Trends 2026 - UX Studio Team](https://www.uxstudioteam.com/ux-blog/ui-trends-2019)
|
|
306
|
+
- [12 UI/UX Design Trends - Index.dev](https://www.index.dev/blog/ui-ux-design-trends)
|
|
307
|
+
- [Typography Trends 2026 - Wannathis](https://wannathis.one/blog/top-typography-trends-2026-for-designers)
|
|
308
|
+
- [Color Trends 2026 - Lounge Lizard](https://www.loungelizard.com/blog/web-design-color-trends/)
|
|
309
|
+
- [Motion UI Trends 2026 - Loma Technology](https://lomatechnology.com/blog/motion-ui-trends-2026/2911)
|
|
310
|
+
- [Motion Library](https://motion.dev/)
|