@kood/claude-code 0.1.6 → 0.1.9
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 +109 -216
- package/package.json +8 -2
- package/templates/hono/CLAUDE.md +59 -328
- package/templates/hono/docs/architecture/architecture.md +93 -747
- package/templates/hono/docs/deployment/cloudflare.md +59 -513
- package/templates/hono/docs/deployment/docker.md +41 -356
- package/templates/hono/docs/deployment/index.md +54 -190
- package/templates/hono/docs/deployment/railway.md +36 -306
- package/templates/hono/docs/deployment/vercel.md +49 -434
- package/templates/hono/docs/library/ai-sdk/index.md +53 -290
- package/templates/hono/docs/library/ai-sdk/openrouter.md +19 -387
- package/templates/hono/docs/library/ai-sdk/providers.md +28 -394
- package/templates/hono/docs/library/ai-sdk/streaming.md +52 -353
- package/templates/hono/docs/library/ai-sdk/structured-output.md +63 -395
- package/templates/hono/docs/library/ai-sdk/tools.md +62 -431
- package/templates/hono/docs/library/hono/env-setup.md +24 -313
- package/templates/hono/docs/library/hono/error-handling.md +34 -295
- package/templates/hono/docs/library/hono/index.md +29 -121
- package/templates/hono/docs/library/hono/middleware.md +21 -188
- package/templates/hono/docs/library/hono/rpc.md +40 -341
- package/templates/hono/docs/library/hono/validation.md +35 -195
- package/templates/hono/docs/library/pino/index.md +42 -333
- package/templates/hono/docs/library/prisma/cloudflare-d1.md +64 -367
- package/templates/hono/docs/library/prisma/config.md +19 -260
- package/templates/hono/docs/library/prisma/index.md +67 -320
- package/templates/hono/docs/library/zod/index.md +53 -257
- package/templates/npx/CLAUDE.md +62 -274
- package/templates/npx/docs/references/patterns.md +160 -0
- package/templates/tanstack-start/CLAUDE.md +100 -256
- package/templates/tanstack-start/docs/architecture/architecture.md +44 -589
- package/templates/tanstack-start/docs/deployment/cloudflare.md +37 -424
- package/templates/tanstack-start/docs/deployment/index.md +57 -286
- package/templates/tanstack-start/docs/deployment/nitro.md +36 -318
- package/templates/tanstack-start/docs/deployment/railway.md +40 -409
- package/templates/tanstack-start/docs/deployment/vercel.md +43 -465
- package/templates/tanstack-start/docs/design/components.md +77 -311
- package/templates/tanstack-start/docs/design/index.md +113 -69
- package/templates/tanstack-start/docs/design/safe-area.md +51 -250
- package/templates/tanstack-start/docs/design/tailwind-setup.md +45 -359
- package/templates/tanstack-start/docs/guides/conventions.md +103 -0
- package/templates/tanstack-start/docs/guides/env-setup.md +34 -340
- package/templates/tanstack-start/docs/guides/getting-started.md +22 -209
- package/templates/tanstack-start/docs/guides/hooks.md +166 -0
- package/templates/tanstack-start/docs/guides/routes.md +166 -0
- package/templates/tanstack-start/docs/guides/services.md +143 -0
- package/templates/tanstack-start/docs/library/better-auth/2fa.md +27 -115
- package/templates/tanstack-start/docs/library/better-auth/advanced.md +22 -105
- package/templates/tanstack-start/docs/library/better-auth/index.md +17 -66
- package/templates/tanstack-start/docs/library/better-auth/plugins.md +11 -88
- package/templates/tanstack-start/docs/library/better-auth/session.md +12 -92
- package/templates/tanstack-start/docs/library/better-auth/setup.md +9 -91
- package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +30 -358
- package/templates/tanstack-start/docs/library/prisma/config.md +27 -327
- package/templates/tanstack-start/docs/library/prisma/crud.md +46 -174
- package/templates/tanstack-start/docs/library/prisma/index.md +23 -113
- package/templates/tanstack-start/docs/library/prisma/relations.md +31 -153
- package/templates/tanstack-start/docs/library/prisma/schema.md +40 -217
- package/templates/tanstack-start/docs/library/prisma/setup.md +12 -112
- package/templates/tanstack-start/docs/library/prisma/transactions.md +20 -110
- package/templates/tanstack-start/docs/library/tanstack-query/index.md +26 -97
- package/templates/tanstack-start/docs/library/tanstack-query/invalidation.md +28 -107
- package/templates/tanstack-start/docs/library/tanstack-query/optimistic-updates.md +44 -146
- package/templates/tanstack-start/docs/library/tanstack-query/use-mutation.md +33 -127
- package/templates/tanstack-start/docs/library/tanstack-query/use-query.md +49 -149
- package/templates/tanstack-start/docs/library/tanstack-start/auth-patterns.md +19 -112
- package/templates/tanstack-start/docs/library/tanstack-start/index.md +33 -80
- package/templates/tanstack-start/docs/library/tanstack-start/middleware.md +28 -106
- package/templates/tanstack-start/docs/library/tanstack-start/routing.md +21 -118
- package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +34 -246
- package/templates/tanstack-start/docs/library/tanstack-start/setup.md +6 -39
- package/templates/tanstack-start/docs/library/zod/complex-types.md +32 -156
- package/templates/tanstack-start/docs/library/zod/index.md +31 -144
- package/templates/tanstack-start/docs/library/zod/transforms.md +20 -129
- package/templates/tanstack-start/docs/library/zod/validation.md +39 -155
- package/templates/hono/docs/commands/git.md +0 -145
- package/templates/hono/docs/mcp/context7.md +0 -106
- package/templates/hono/docs/mcp/index.md +0 -176
- package/templates/hono/docs/mcp/sequential-thinking.md +0 -101
- package/templates/hono/docs/mcp/serena.md +0 -269
- package/templates/hono/docs/mcp/sgrep.md +0 -105
- package/templates/hono/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/hono/docs/skills/gemini-review/references/checklists.md +0 -136
- package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +0 -303
- package/templates/npx/docs/commands/git.md +0 -145
- package/templates/npx/docs/mcp/index.md +0 -60
- package/templates/npx/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/npx/docs/skills/gemini-review/references/checklists.md +0 -134
- package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +0 -301
- package/templates/tanstack-start/docs/commands/git.md +0 -145
- package/templates/tanstack-start/docs/design/accessibility.md +0 -433
- package/templates/tanstack-start/docs/design/color.md +0 -235
- package/templates/tanstack-start/docs/design/spacing.md +0 -341
- package/templates/tanstack-start/docs/design/typography.md +0 -324
- package/templates/tanstack-start/docs/guides/best-practices.md +0 -950
- package/templates/tanstack-start/docs/guides/husky-lint-staged.md +0 -303
- package/templates/tanstack-start/docs/guides/prettier.md +0 -189
- package/templates/tanstack-start/docs/guides/project-templates.md +0 -710
- package/templates/tanstack-start/docs/library/tanstack-query/setup.md +0 -107
- package/templates/tanstack-start/docs/library/zod/basic-types.md +0 -186
- package/templates/tanstack-start/docs/mcp/context7.md +0 -204
- package/templates/tanstack-start/docs/mcp/index.md +0 -177
- package/templates/tanstack-start/docs/mcp/sequential-thinking.md +0 -180
- package/templates/tanstack-start/docs/mcp/serena.md +0 -269
- package/templates/tanstack-start/docs/mcp/sgrep.md +0 -174
- package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +0 -220
- package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +0 -144
- package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +0 -292
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
현재 git 상태를 확인하고, 아래 규칙에 따라 작업을 진행해주세요.
|
|
2
|
-
|
|
3
|
-
**추가 지시사항**: $ARGUMENTS
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 실행 절차
|
|
8
|
-
|
|
9
|
-
### 추가 지시사항이 없는 경우 (기본 동작)
|
|
10
|
-
1. `git status`로 현재 상태 확인
|
|
11
|
-
2. `git diff`로 변경 내용 분석
|
|
12
|
-
3. 스테이징 안 된 변경사항 → `git add`
|
|
13
|
-
4. 커밋 안 된 변경사항 → 논리적 단위로 분리하여 `git commit`
|
|
14
|
-
5. 최종 `git status`로 완료 확인
|
|
15
|
-
|
|
16
|
-
### 추가 지시사항이 있는 경우
|
|
17
|
-
- 사용자의 지시사항을 우선적으로 따름
|
|
18
|
-
- 예: `/git push` → push 진행, `/git 특정파일만 커밋` → 해당 파일만 처리
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## ⛔ NEVER (절대 금지)
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
❌ 커밋에 "Generated with Claude Code" 포함
|
|
26
|
-
❌ 커밋에 "🤖" 또는 AI 관련 이모지 포함
|
|
27
|
-
❌ 커밋에 "Co-Authored-By:" 헤더 포함
|
|
28
|
-
❌ 커밋에 AI/봇이 작성했다는 어떤 표시도 포함
|
|
29
|
-
❌ 커밋 메시지 여러 줄 작성
|
|
30
|
-
❌ 커밋 메시지에 이모지 사용
|
|
31
|
-
❌ 커밋 메시지에 마침표(.) 사용
|
|
32
|
-
❌ 여러 작업을 하나의 커밋으로 퉁치기
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## ✅ ALWAYS (필수)
|
|
38
|
-
|
|
39
|
-
### 커밋 형식
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
<prefix>: <설명>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**한 줄로 간결하게** 작성합니다. 본문이나 푸터는 작성하지 않습니다.
|
|
46
|
-
|
|
47
|
-
### ⭐ 커밋 분리 원칙
|
|
48
|
-
|
|
49
|
-
**하나의 커밋 = 하나의 논리적 변경 단위**
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# ❌ 잘못된 방식: 모든 작업을 하나로 퉁침
|
|
53
|
-
git add .
|
|
54
|
-
git commit -m "feat: 여러 기능 추가"
|
|
55
|
-
|
|
56
|
-
# ✅ 올바른 방식: 논리적 단위로 분리
|
|
57
|
-
git add src/auth/
|
|
58
|
-
git commit -m "feat: 사용자 인증 기능 추가"
|
|
59
|
-
|
|
60
|
-
git add src/users/
|
|
61
|
-
git commit -m "feat: 사용자 관리 기능 추가"
|
|
62
|
-
|
|
63
|
-
git add docs/
|
|
64
|
-
git commit -m "docs: API 문서 업데이트"
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## 🏷 Prefix 목록
|
|
70
|
-
|
|
71
|
-
| Prefix | 용도 | 예시 |
|
|
72
|
-
|--------|------|------|
|
|
73
|
-
| `feat` | 새로운 기능 | `feat: 사용자 인증 기능 추가` |
|
|
74
|
-
| `fix` | 버그 수정 | `fix: 토큰 검증 오류 수정` |
|
|
75
|
-
| `refactor` | 리팩토링 | `refactor: 인증 로직 분리` |
|
|
76
|
-
| `style` | 코드 스타일 | `style: prettier 적용` |
|
|
77
|
-
| `docs` | 문서 수정 | `docs: API 문서 업데이트` |
|
|
78
|
-
| `test` | 테스트 | `test: 인증 테스트 추가` |
|
|
79
|
-
| `chore` | 빌드/설정 | `chore: 의존성 업데이트` |
|
|
80
|
-
| `perf` | 성능 개선 | `perf: 쿼리 최적화` |
|
|
81
|
-
| `ci` | CI/CD | `ci: GitHub Actions 추가` |
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## ✅ 올바른 예시
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
feat: 사용자 로그인 기능 추가
|
|
89
|
-
fix: 세션 만료 오류 수정
|
|
90
|
-
refactor: 서비스 클래스 구조 개선
|
|
91
|
-
docs: README 설치 가이드 추가
|
|
92
|
-
chore: 의존성 버전 업그레이드
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## ❌ 잘못된 예시
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
# prefix 없음
|
|
101
|
-
사용자 인증 기능 추가함
|
|
102
|
-
|
|
103
|
-
# 마침표 불필요
|
|
104
|
-
feat: 사용자 인증 추가.
|
|
105
|
-
|
|
106
|
-
# 대문자 사용
|
|
107
|
-
FEAT: 사용자 인증 추가
|
|
108
|
-
|
|
109
|
-
# scope 불필요
|
|
110
|
-
feat(auth): 인증 추가
|
|
111
|
-
|
|
112
|
-
# AI 작성 표시 (절대 금지!)
|
|
113
|
-
feat: 로그인 기능 추가
|
|
114
|
-
|
|
115
|
-
🤖 Generated with Claude Code
|
|
116
|
-
|
|
117
|
-
# Co-Author 표시 (절대 금지!)
|
|
118
|
-
feat: 로그인 기능 추가
|
|
119
|
-
|
|
120
|
-
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
121
|
-
|
|
122
|
-
# 여러 줄 본문 (금지)
|
|
123
|
-
feat: 로그인 기능 추가
|
|
124
|
-
|
|
125
|
-
- 이메일 인증 추가
|
|
126
|
-
- 세션 관리 구현
|
|
127
|
-
|
|
128
|
-
# 여러 작업을 하나로 퉁침 (금지)
|
|
129
|
-
feat: 로그인, 회원가입, 프로필 기능 추가
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## 📦 커밋 분리 가이드
|
|
135
|
-
|
|
136
|
-
### 언제 커밋을 분리해야 하나요?
|
|
137
|
-
|
|
138
|
-
| 상황 | 커밋 분리 |
|
|
139
|
-
|------|----------|
|
|
140
|
-
| 서로 다른 기능 구현 | ✅ 분리 |
|
|
141
|
-
| 버그 수정 + 새 기능 | ✅ 분리 |
|
|
142
|
-
| 코드 변경 + 문서 변경 | ✅ 분리 |
|
|
143
|
-
| 리팩토링 + 기능 추가 | ✅ 분리 |
|
|
144
|
-
| 동일 기능의 관련 파일들 | 🔄 묶어도 됨 |
|
|
145
|
-
| 동일 기능의 타입 + 구현 | 🔄 묶어도 됨 |
|
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
# 접근성 (Accessibility)
|
|
2
|
-
|
|
3
|
-
> **상위 문서**: [UI/UX 디자인 가이드](./index.md)
|
|
4
|
-
|
|
5
|
-
접근성(A11y)은 장애가 있는 사용자도 웹사이트를 사용할 수 있게 만드는 것입니다. 이는 윤리적 의무이자 법적 요구사항이기도 합니다.
|
|
6
|
-
|
|
7
|
-
## 왜 접근성이 중요한가?
|
|
8
|
-
|
|
9
|
-
### 접근성이 필요한 사용자
|
|
10
|
-
|
|
11
|
-
| 유형 | 예시 | 필요한 지원 |
|
|
12
|
-
|------|------|------------|
|
|
13
|
-
| **시각 장애** | 전맹, 저시력, 색맹 | 스크린 리더, 고대비, 큰 텍스트 |
|
|
14
|
-
| **청각 장애** | 난청, 전농 | 자막, 시각적 알림 |
|
|
15
|
-
| **운동 장애** | 손떨림, 마비 | 키보드 네비게이션, 큰 클릭 영역 |
|
|
16
|
-
| **인지 장애** | 읽기 장애, 집중력 장애 | 단순한 언어, 명확한 구조 |
|
|
17
|
-
|
|
18
|
-
### 접근성의 이점
|
|
19
|
-
|
|
20
|
-
- 법적 준수 (ADA, 장애인차별금지법)
|
|
21
|
-
- 더 넓은 사용자층
|
|
22
|
-
- SEO 개선 (검색 엔진도 접근성 기준 활용)
|
|
23
|
-
- 전반적인 UX 향상 (모든 사용자에게 도움)
|
|
24
|
-
|
|
25
|
-
## WCAG 기준
|
|
26
|
-
|
|
27
|
-
WCAG(Web Content Accessibility Guidelines)는 웹 접근성의 국제 표준입니다.
|
|
28
|
-
|
|
29
|
-
### 준수 수준
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
Level A - 최소 기준 (필수)
|
|
33
|
-
Level AA - 권장 기준 (일반적 목표)
|
|
34
|
-
Level AAA - 최고 기준 (특수한 경우)
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### 4가지 원칙 (POUR)
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
P - Perceivable (인식 가능) 모든 정보를 인식할 수 있어야 함
|
|
41
|
-
O - Operable (조작 가능) 모든 기능을 조작할 수 있어야 함
|
|
42
|
-
U - Understandable (이해 가능) 내용을 이해할 수 있어야 함
|
|
43
|
-
R - Robust (견고함) 다양한 기술에서 동작해야 함
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## 색상 접근성
|
|
47
|
-
|
|
48
|
-
### 색상 대비 요구사항
|
|
49
|
-
|
|
50
|
-
| 텍스트 유형 | 최소 대비 (AA) | 권장 대비 (AAA) |
|
|
51
|
-
|------------|---------------|----------------|
|
|
52
|
-
| 일반 텍스트 (< 18px) | 4.5:1 | 7:1 |
|
|
53
|
-
| 큰 텍스트 (≥ 18px bold, ≥ 24px) | 3:1 | 4.5:1 |
|
|
54
|
-
| UI 컴포넌트, 그래픽 | 3:1 | - |
|
|
55
|
-
|
|
56
|
-
### 안전한 색상 조합
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
// ✅ 좋은 대비
|
|
60
|
-
<p className="text-gray-900 bg-white">검정 on 흰색 (21:1)</p>
|
|
61
|
-
<p className="text-white bg-blue-700">흰색 on 진한 파랑 (8.6:1)</p>
|
|
62
|
-
<p className="text-gray-700 bg-gray-100">진한 회색 on 밝은 회색 (5.4:1)</p>
|
|
63
|
-
|
|
64
|
-
// ❌ 나쁜 대비
|
|
65
|
-
<p className="text-gray-400 bg-white">밝은 회색 on 흰색 (2.7:1)</p>
|
|
66
|
-
<p className="text-yellow-500 bg-white">노란색 on 흰색 (1.3:1)</p>
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 색상만으로 정보 전달 금지
|
|
70
|
-
|
|
71
|
-
```tsx
|
|
72
|
-
// ❌ 나쁜 예 - 색상만으로 구분
|
|
73
|
-
<span className="text-red-600">오류</span>
|
|
74
|
-
<span className="text-green-600">성공</span>
|
|
75
|
-
|
|
76
|
-
// ✅ 좋은 예 - 아이콘/텍스트 병행
|
|
77
|
-
<span className="text-red-600 flex items-center gap-1">
|
|
78
|
-
<XCircleIcon className="w-4 h-4" />
|
|
79
|
-
오류가 발생했습니다
|
|
80
|
-
</span>
|
|
81
|
-
<span className="text-green-600 flex items-center gap-1">
|
|
82
|
-
<CheckCircleIcon className="w-4 h-4" />
|
|
83
|
-
성공적으로 저장됨
|
|
84
|
-
</span>
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## 키보드 접근성
|
|
88
|
-
|
|
89
|
-
### 모든 기능은 키보드로 가능해야 함
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
Tab 다음 요소로 이동
|
|
93
|
-
Shift+Tab 이전 요소로 이동
|
|
94
|
-
Enter 버튼 클릭, 링크 이동
|
|
95
|
-
Space 체크박스 토글, 버튼 클릭
|
|
96
|
-
Escape 모달 닫기, 취소
|
|
97
|
-
Arrow 드롭다운, 슬라이더 조작
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### 포커스 표시
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
// ✅ 명확한 포커스 스타일
|
|
104
|
-
<button className="focus:outline-none focus:ring-2 focus:ring-blue-500
|
|
105
|
-
focus:ring-offset-2">
|
|
106
|
-
버튼
|
|
107
|
-
</button>
|
|
108
|
-
|
|
109
|
-
// 입력 필드
|
|
110
|
-
<input className="focus:outline-none focus:ring-2 focus:ring-blue-500
|
|
111
|
-
focus:border-blue-500" />
|
|
112
|
-
|
|
113
|
-
// ❌ 포커스 제거 금지
|
|
114
|
-
<button className="outline-none focus:outline-none">
|
|
115
|
-
{/* 접근성 위반! */}
|
|
116
|
-
</button>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### 포커스 순서
|
|
120
|
-
|
|
121
|
-
```tsx
|
|
122
|
-
// 논리적인 탭 순서 유지
|
|
123
|
-
<form>
|
|
124
|
-
<input tabIndex={0} /> {/* 1번째 */}
|
|
125
|
-
<input tabIndex={0} /> {/* 2번째 */}
|
|
126
|
-
<button tabIndex={0}>취소</button> {/* 3번째 */}
|
|
127
|
-
<button tabIndex={0}>저장</button> {/* 4번째 */}
|
|
128
|
-
</form>
|
|
129
|
-
|
|
130
|
-
// ❌ tabIndex로 순서 강제 변경 피하기
|
|
131
|
-
<button tabIndex={2}>저장</button>
|
|
132
|
-
<button tabIndex={1}>취소</button>
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### 포커스 트랩 (모달)
|
|
136
|
-
|
|
137
|
-
```tsx
|
|
138
|
-
// 모달이 열리면 포커스가 모달 안에만 머물러야 함
|
|
139
|
-
const Modal = ({ isOpen, onClose }) => {
|
|
140
|
-
const modalRef = useRef(null)
|
|
141
|
-
|
|
142
|
-
useEffect(() => {
|
|
143
|
-
if (isOpen) {
|
|
144
|
-
// 모달 열릴 때 첫 번째 요소에 포커스
|
|
145
|
-
modalRef.current?.querySelector('button')?.focus()
|
|
146
|
-
}
|
|
147
|
-
}, [isOpen])
|
|
148
|
-
|
|
149
|
-
const handleKeyDown = (e) => {
|
|
150
|
-
if (e.key === 'Escape') onClose()
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return (
|
|
154
|
-
<div
|
|
155
|
-
ref={modalRef}
|
|
156
|
-
role="dialog"
|
|
157
|
-
aria-modal="true"
|
|
158
|
-
onKeyDown={handleKeyDown}
|
|
159
|
-
>
|
|
160
|
-
{/* 모달 내용 */}
|
|
161
|
-
</div>
|
|
162
|
-
)
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## 시맨틱 HTML
|
|
167
|
-
|
|
168
|
-
### 올바른 HTML 요소 사용
|
|
169
|
-
|
|
170
|
-
```tsx
|
|
171
|
-
// ✅ 시맨틱 HTML
|
|
172
|
-
<header>...</header>
|
|
173
|
-
<nav>...</nav>
|
|
174
|
-
<main>
|
|
175
|
-
<article>
|
|
176
|
-
<h1>제목</h1>
|
|
177
|
-
<section>...</section>
|
|
178
|
-
</article>
|
|
179
|
-
</main>
|
|
180
|
-
<footer>...</footer>
|
|
181
|
-
|
|
182
|
-
// ❌ div 남용
|
|
183
|
-
<div className="header">...</div>
|
|
184
|
-
<div className="nav">...</div>
|
|
185
|
-
<div className="main">...</div>
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### 제목 계층
|
|
189
|
-
|
|
190
|
-
```tsx
|
|
191
|
-
// ✅ 올바른 제목 순서
|
|
192
|
-
<h1>페이지 제목</h1>
|
|
193
|
-
<h2>섹션 1</h2>
|
|
194
|
-
<h3>하위 섹션 1-1</h3>
|
|
195
|
-
<h2>섹션 2</h2>
|
|
196
|
-
|
|
197
|
-
// ❌ 제목 레벨 건너뛰기
|
|
198
|
-
<h1>페이지 제목</h1>
|
|
199
|
-
<h3>섹션</h3> {/* h2를 건너뜀 */}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### 버튼 vs 링크
|
|
203
|
-
|
|
204
|
-
```tsx
|
|
205
|
-
// 버튼: 동작 수행
|
|
206
|
-
<button onClick={handleSave}>저장</button>
|
|
207
|
-
|
|
208
|
-
// 링크: 페이지 이동
|
|
209
|
-
<a href="/about">소개 페이지</a>
|
|
210
|
-
|
|
211
|
-
// ❌ 잘못된 사용
|
|
212
|
-
<div onClick={handleSave}>저장</div> {/* div를 버튼처럼 */}
|
|
213
|
-
<a onClick={handleAction}>클릭</a> {/* 링크를 버튼처럼 */}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## ARIA 속성
|
|
217
|
-
|
|
218
|
-
### 필수 ARIA 사용
|
|
219
|
-
|
|
220
|
-
```tsx
|
|
221
|
-
// 레이블 연결
|
|
222
|
-
<label htmlFor="email">이메일</label>
|
|
223
|
-
<input id="email" type="email" />
|
|
224
|
-
|
|
225
|
-
// 또는 aria-label 사용
|
|
226
|
-
<input aria-label="검색어 입력" type="search" />
|
|
227
|
-
|
|
228
|
-
// 설명 연결
|
|
229
|
-
<input aria-describedby="email-hint" />
|
|
230
|
-
<p id="email-hint">업무용 이메일을 입력하세요</p>
|
|
231
|
-
|
|
232
|
-
// 에러 상태
|
|
233
|
-
<input aria-invalid="true" aria-describedby="email-error" />
|
|
234
|
-
<p id="email-error" role="alert">올바른 이메일을 입력하세요</p>
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### 상태 알림
|
|
238
|
-
|
|
239
|
-
```tsx
|
|
240
|
-
// 동적 콘텐츠 변경 알림
|
|
241
|
-
<div aria-live="polite">
|
|
242
|
-
{/* 변경되면 스크린 리더가 읽어줌 */}
|
|
243
|
-
{message}
|
|
244
|
-
</div>
|
|
245
|
-
|
|
246
|
-
// 긴급 알림
|
|
247
|
-
<div aria-live="assertive" role="alert">
|
|
248
|
-
{errorMessage}
|
|
249
|
-
</div>
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### 숨김 처리
|
|
253
|
-
|
|
254
|
-
```tsx
|
|
255
|
-
// 시각적으로만 숨김 (스크린 리더는 읽음)
|
|
256
|
-
<span className="sr-only">메뉴 열기</span>
|
|
257
|
-
|
|
258
|
-
// Tailwind의 sr-only 클래스
|
|
259
|
-
.sr-only {
|
|
260
|
-
position: absolute;
|
|
261
|
-
width: 1px;
|
|
262
|
-
height: 1px;
|
|
263
|
-
padding: 0;
|
|
264
|
-
margin: -1px;
|
|
265
|
-
overflow: hidden;
|
|
266
|
-
clip: rect(0, 0, 0, 0);
|
|
267
|
-
border: 0;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// 스크린 리더에서도 숨김
|
|
271
|
-
<div aria-hidden="true">장식용 아이콘</div>
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
## 폼 접근성
|
|
275
|
-
|
|
276
|
-
### 레이블 필수
|
|
277
|
-
|
|
278
|
-
```tsx
|
|
279
|
-
// ✅ 명시적 레이블
|
|
280
|
-
<label htmlFor="name">이름</label>
|
|
281
|
-
<input id="name" type="text" />
|
|
282
|
-
|
|
283
|
-
// ✅ 암묵적 레이블
|
|
284
|
-
<label>
|
|
285
|
-
이름
|
|
286
|
-
<input type="text" />
|
|
287
|
-
</label>
|
|
288
|
-
|
|
289
|
-
// ✅ aria-label (시각적 레이블 없을 때)
|
|
290
|
-
<input type="search" aria-label="사이트 검색" />
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### 에러 처리
|
|
294
|
-
|
|
295
|
-
```tsx
|
|
296
|
-
<div>
|
|
297
|
-
<label htmlFor="email">이메일</label>
|
|
298
|
-
<input
|
|
299
|
-
id="email"
|
|
300
|
-
type="email"
|
|
301
|
-
aria-invalid={hasError}
|
|
302
|
-
aria-describedby={hasError ? "email-error" : undefined}
|
|
303
|
-
className={hasError ? "border-red-500" : "border-gray-300"}
|
|
304
|
-
/>
|
|
305
|
-
{hasError && (
|
|
306
|
-
<p id="email-error" className="text-red-600 text-sm mt-1" role="alert">
|
|
307
|
-
올바른 이메일 형식을 입력하세요
|
|
308
|
-
</p>
|
|
309
|
-
)}
|
|
310
|
-
</div>
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### 필수 필드 표시
|
|
314
|
-
|
|
315
|
-
```tsx
|
|
316
|
-
<label htmlFor="email">
|
|
317
|
-
이메일 <span className="text-red-600" aria-hidden="true">*</span>
|
|
318
|
-
<span className="sr-only">(필수)</span>
|
|
319
|
-
</label>
|
|
320
|
-
<input id="email" required aria-required="true" />
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
## 이미지 접근성
|
|
324
|
-
|
|
325
|
-
### 대체 텍스트 (alt)
|
|
326
|
-
|
|
327
|
-
```tsx
|
|
328
|
-
// 정보 전달 이미지 - 설명 필요
|
|
329
|
-
<img src="chart.png" alt="2024년 매출 추이: 1월 100만원에서 12월 500만원으로 성장" />
|
|
330
|
-
|
|
331
|
-
// 장식용 이미지 - 빈 alt
|
|
332
|
-
<img src="decorative.png" alt="" />
|
|
333
|
-
|
|
334
|
-
// 아이콘 버튼 - 기능 설명
|
|
335
|
-
<button aria-label="닫기">
|
|
336
|
-
<img src="close.svg" alt="" />
|
|
337
|
-
</button>
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
## 터치 접근성
|
|
341
|
-
|
|
342
|
-
### 최소 터치 영역
|
|
343
|
-
|
|
344
|
-
```tsx
|
|
345
|
-
// 최소 44x44px 터치 영역
|
|
346
|
-
<button className="min-w-[44px] min-h-[44px] p-2">
|
|
347
|
-
<Icon className="w-6 h-6" />
|
|
348
|
-
</button>
|
|
349
|
-
|
|
350
|
-
// 작은 체크박스도 터치 영역 확보
|
|
351
|
-
<label className="flex items-center gap-2 p-2 -m-2 cursor-pointer">
|
|
352
|
-
<input type="checkbox" className="w-4 h-4" />
|
|
353
|
-
<span>동의합니다</span>
|
|
354
|
-
</label>
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### 터치 타겟 간격
|
|
358
|
-
|
|
359
|
-
```tsx
|
|
360
|
-
// 터치 타겟 사이 최소 8px 간격
|
|
361
|
-
<div className="flex gap-2">
|
|
362
|
-
<button className="p-3">버튼 1</button>
|
|
363
|
-
<button className="p-3">버튼 2</button>
|
|
364
|
-
</div>
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
## 접근성 테스트
|
|
368
|
-
|
|
369
|
-
### 자동화 도구
|
|
370
|
-
|
|
371
|
-
| 도구 | 용도 |
|
|
372
|
-
|------|------|
|
|
373
|
-
| **axe DevTools** | 브라우저 확장, 자동 검사 |
|
|
374
|
-
| **Lighthouse** | Chrome 내장, 접근성 점수 |
|
|
375
|
-
| **WAVE** | 시각적 피드백 |
|
|
376
|
-
| **eslint-plugin-jsx-a11y** | 코드 레벨 검사 |
|
|
377
|
-
|
|
378
|
-
### 수동 테스트
|
|
379
|
-
|
|
380
|
-
```
|
|
381
|
-
1. 키보드만으로 모든 기능 사용 가능한가?
|
|
382
|
-
2. Tab 순서가 논리적인가?
|
|
383
|
-
3. 포커스 표시가 명확한가?
|
|
384
|
-
4. 스크린 리더로 내용을 이해할 수 있는가?
|
|
385
|
-
5. 200% 확대해도 사용 가능한가?
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### ESLint 설정
|
|
389
|
-
|
|
390
|
-
```bash
|
|
391
|
-
yarn add -D eslint-plugin-jsx-a11y
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
```js
|
|
395
|
-
// eslint.config.js
|
|
396
|
-
import jsxA11y from 'eslint-plugin-jsx-a11y'
|
|
397
|
-
|
|
398
|
-
export default [
|
|
399
|
-
{
|
|
400
|
-
plugins: { 'jsx-a11y': jsxA11y },
|
|
401
|
-
rules: {
|
|
402
|
-
'jsx-a11y/alt-text': 'error',
|
|
403
|
-
'jsx-a11y/anchor-has-content': 'error',
|
|
404
|
-
'jsx-a11y/click-events-have-key-events': 'error',
|
|
405
|
-
'jsx-a11y/no-noninteractive-element-interactions': 'error',
|
|
406
|
-
},
|
|
407
|
-
},
|
|
408
|
-
]
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
## 체크리스트
|
|
412
|
-
|
|
413
|
-
### 필수 (Level A)
|
|
414
|
-
|
|
415
|
-
- [ ] 모든 이미지에 alt 텍스트
|
|
416
|
-
- [ ] 모든 폼 요소에 레이블
|
|
417
|
-
- [ ] 키보드로 모든 기능 접근 가능
|
|
418
|
-
- [ ] 포커스 표시 유지
|
|
419
|
-
- [ ] 색상만으로 정보 전달하지 않음
|
|
420
|
-
|
|
421
|
-
### 권장 (Level AA)
|
|
422
|
-
|
|
423
|
-
- [ ] 텍스트 대비 4.5:1 이상
|
|
424
|
-
- [ ] 페이지 제목 명확
|
|
425
|
-
- [ ] 제목 계층 논리적
|
|
426
|
-
- [ ] 에러 메시지 명확
|
|
427
|
-
- [ ] 200% 확대 시 가로 스크롤 없음
|
|
428
|
-
|
|
429
|
-
### 최고 수준 (Level AAA)
|
|
430
|
-
|
|
431
|
-
- [ ] 텍스트 대비 7:1 이상
|
|
432
|
-
- [ ] 읽기 수준 고려
|
|
433
|
-
- [ ] 약어 설명 제공
|