codymaster 4.4.4 → 4.5.1

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.
Files changed (190) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +29 -14
  3. package/commands/demo.md +1 -1
  4. package/dist/context-bus.js +70 -0
  5. package/dist/context-db.js +265 -0
  6. package/dist/continuity.js +12 -0
  7. package/dist/file-watcher.js +79 -0
  8. package/dist/index.js +152 -1
  9. package/dist/l0-indexer.js +158 -0
  10. package/dist/mcp-context-server.js +400 -0
  11. package/dist/migrate-json-to-sqlite.js +126 -0
  12. package/dist/skill-chain.js +19 -3
  13. package/dist/token-budget.js +108 -0
  14. package/dist/uri-resolver.js +203 -0
  15. package/package.json +7 -1
  16. package/skills/_shared/helpers.md +50 -14
  17. package/skills/cm-autopilot/SKILL.md +29 -0
  18. package/skills/cm-autopilot/scripts/autopilot.py +190 -0
  19. package/skills/cm-continuity/SKILL.md +90 -28
  20. package/skills/cm-quality-gate/SKILL.md +11 -1
  21. package/skills/cm-safe-deploy/SKILL.md +38 -2
  22. package/skills/cm-security-gate/SKILL.md +158 -34
  23. package/skills/cm-skill-chain/SKILL.md +47 -1
  24. package/skills/cm-start/SKILL.md +11 -2
  25. package/skills/cm-test-gate/SKILL.md +3 -0
  26. package/skills/boxme-git-config/SKILL.md +0 -56
  27. package/skills/boxme-local-dev/SKILL.md +0 -66
  28. package/skills/jobs-to-be-done/SKILL.md +0 -266
  29. package/skills/jobs-to-be-done/references/case-studies.md +0 -154
  30. package/skills/jobs-to-be-done/references/competitive-strategy.md +0 -280
  31. package/skills/jobs-to-be-done/references/diagnostics.md +0 -158
  32. package/skills/jobs-to-be-done/references/innovation-process.md +0 -392
  33. package/skills/jobs-to-be-done/references/organizational-change.md +0 -328
  34. package/skills/marketplace-report-crawler/SKILL.md +0 -176
  35. package/skills/marketplace-report-crawler/config/accounts.json +0 -41
  36. package/skills/marketplace-report-crawler/config/report-types.json +0 -422
  37. package/skills/marketplace-report-crawler/config/sessions.json +0 -3
  38. package/skills/marketplace-report-crawler/scripts/ab-wrapper.sh +0 -102
  39. package/skills/marketplace-report-crawler/scripts/browser-actions/lazada/lazada-actions.js +0 -114
  40. package/skills/marketplace-report-crawler/scripts/browser-actions/shopee/shopee-actions.js +0 -94
  41. package/skills/marketplace-report-crawler/scripts/browser-actions/tiktok/tiktok-actions.js +0 -272
  42. package/skills/marketplace-report-crawler/scripts/crawl-runner.js +0 -281
  43. package/skills/marketplace-report-crawler/scripts/session-check.sh +0 -72
  44. package/skills/marketplace-report-crawler/scripts/session-manager.sh +0 -349
  45. package/skills/marketplace-report-crawler/scripts/setup-folders.sh +0 -83
  46. package/skills/medical-research/SKILL.md +0 -194
  47. package/skills/medical-research/scripts/evidence_checker.py +0 -288
  48. package/skills/mom-test/SKILL.md +0 -267
  49. package/skills/mom-test/references/avoiding-bad-data.md +0 -221
  50. package/skills/mom-test/references/case-studies.md +0 -306
  51. package/skills/mom-test/references/commitment-advancement.md +0 -219
  52. package/skills/mom-test/references/finding-conversations.md +0 -251
  53. package/skills/mom-test/references/processing-learning.md +0 -256
  54. package/skills/mom-test/references/question-patterns.md +0 -198
  55. package/skills/pandasai-analytics/SKILL.md +0 -251
  56. package/skills/release-it/SKILL.md +0 -235
  57. package/skills/release-it/references/anti-patterns.md +0 -279
  58. package/skills/release-it/references/capacity-planning.md +0 -285
  59. package/skills/release-it/references/chaos-engineering.md +0 -325
  60. package/skills/release-it/references/deployment-strategies.md +0 -331
  61. package/skills/release-it/references/observability.md +0 -301
  62. package/skills/release-it/references/stability-patterns.md +0 -355
  63. package/skills/skill-creator-ultra/.agents/workflows/skill-audit.md +0 -37
  64. package/skills/skill-creator-ultra/.agents/workflows/skill-compare.md +0 -34
  65. package/skills/skill-creator-ultra/.agents/workflows/skill-export.md +0 -51
  66. package/skills/skill-creator-ultra/.agents/workflows/skill-generate.md +0 -39
  67. package/skills/skill-creator-ultra/.agents/workflows/skill-scaffold.md +0 -52
  68. package/skills/skill-creator-ultra/.agents/workflows/skill-simulate.md +0 -25
  69. package/skills/skill-creator-ultra/.agents/workflows/skill-stats.md +0 -31
  70. package/skills/skill-creator-ultra/.agents/workflows/skill-validate.md +0 -25
  71. package/skills/skill-creator-ultra/README.md +0 -1242
  72. package/skills/skill-creator-ultra/SKILL.md +0 -388
  73. package/skills/skill-creator-ultra/agents/analyzer.md +0 -274
  74. package/skills/skill-creator-ultra/agents/comparator.md +0 -202
  75. package/skills/skill-creator-ultra/agents/grader.md +0 -223
  76. package/skills/skill-creator-ultra/assets/eval_review.html +0 -146
  77. package/skills/skill-creator-ultra/eval-viewer/generate_review.py +0 -471
  78. package/skills/skill-creator-ultra/eval-viewer/viewer.html +0 -1325
  79. package/skills/skill-creator-ultra/examples/example_anthropic_frontend.md +0 -109
  80. package/skills/skill-creator-ultra/examples/example_anthropic_pdf.md +0 -116
  81. package/skills/skill-creator-ultra/examples/example_api_docs.md +0 -189
  82. package/skills/skill-creator-ultra/examples/example_db_migration.md +0 -253
  83. package/skills/skill-creator-ultra/examples/example_git_commit.md +0 -111
  84. package/skills/skill-creator-ultra/install.ps1 +0 -289
  85. package/skills/skill-creator-ultra/install.sh +0 -313
  86. package/skills/skill-creator-ultra/phases/phase1_interview.md +0 -202
  87. package/skills/skill-creator-ultra/phases/phase2_extract.md +0 -55
  88. package/skills/skill-creator-ultra/phases/phase3_detect.md +0 -57
  89. package/skills/skill-creator-ultra/phases/phase4_generate.md +0 -543
  90. package/skills/skill-creator-ultra/phases/phase5_test.md +0 -319
  91. package/skills/skill-creator-ultra/phases/phase6_eval.md +0 -301
  92. package/skills/skill-creator-ultra/phases/phase7_iterate.md +0 -103
  93. package/skills/skill-creator-ultra/phases/phase8_optimize.md +0 -113
  94. package/skills/skill-creator-ultra/resources/advanced_patterns.md +0 -499
  95. package/skills/skill-creator-ultra/resources/anti_patterns.md +0 -376
  96. package/skills/skill-creator-ultra/resources/blueprints.md +0 -498
  97. package/skills/skill-creator-ultra/resources/checklist.md +0 -243
  98. package/skills/skill-creator-ultra/resources/composition_cookbook.md +0 -291
  99. package/skills/skill-creator-ultra/resources/description_optimization.md +0 -90
  100. package/skills/skill-creator-ultra/resources/eval_guide.md +0 -133
  101. package/skills/skill-creator-ultra/resources/industry_questions.md +0 -189
  102. package/skills/skill-creator-ultra/resources/interview_questions.md +0 -200
  103. package/skills/skill-creator-ultra/resources/pattern_detection.md +0 -200
  104. package/skills/skill-creator-ultra/resources/prompt_engineering.md +0 -531
  105. package/skills/skill-creator-ultra/resources/schemas.md +0 -430
  106. package/skills/skill-creator-ultra/resources/script_integration.md +0 -593
  107. package/skills/skill-creator-ultra/resources/scripts_guide.md +0 -339
  108. package/skills/skill-creator-ultra/resources/skill_template.md +0 -124
  109. package/skills/skill-creator-ultra/resources/skill_writing_guide.md +0 -634
  110. package/skills/skill-creator-ultra/resources/versioning_guide.md +0 -193
  111. package/skills/skill-creator-ultra/scripts/ci_eval.py +0 -200
  112. package/skills/skill-creator-ultra/scripts/package_skill.py +0 -165
  113. package/skills/skill-creator-ultra/scripts/simulate_skill.py +0 -398
  114. package/skills/skill-creator-ultra/scripts/skill_audit.py +0 -611
  115. package/skills/skill-creator-ultra/scripts/skill_compare.py +0 -265
  116. package/skills/skill-creator-ultra/scripts/skill_export.py +0 -334
  117. package/skills/skill-creator-ultra/scripts/skill_scaffold.py +0 -403
  118. package/skills/skill-creator-ultra/scripts/skill_stats.py +0 -339
  119. package/skills/skill-creator-ultra/scripts/validate_skill.py +0 -411
  120. package/skills/tailwind-mastery/SKILL.md +0 -229
  121. package/skills/vercel-react-best-practices/AGENTS.md +0 -3373
  122. package/skills/vercel-react-best-practices/README.md +0 -123
  123. package/skills/vercel-react-best-practices/SKILL.md +0 -143
  124. package/skills/vercel-react-best-practices/rules/_sections.md +0 -46
  125. package/skills/vercel-react-best-practices/rules/_template.md +0 -28
  126. package/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  127. package/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
  128. package/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
  129. package/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  130. package/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  131. package/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
  132. package/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  133. package/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  134. package/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  135. package/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  136. package/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  137. package/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  138. package/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  139. package/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  140. package/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  141. package/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  142. package/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  143. package/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
  144. package/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  145. package/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  146. package/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  147. package/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  148. package/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  149. package/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
  150. package/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  151. package/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  152. package/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  153. package/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  154. package/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  155. package/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  156. package/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  157. package/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  158. package/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  159. package/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  160. package/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  161. package/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  162. package/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
  163. package/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
  164. package/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
  165. package/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  166. package/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
  167. package/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  168. package/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  169. package/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
  170. package/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  171. package/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  172. package/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  173. package/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
  174. package/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  175. package/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
  176. package/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
  177. package/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
  178. package/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +0 -64
  179. package/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  180. package/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +0 -59
  181. package/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
  182. package/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  183. package/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
  184. package/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  185. package/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  186. package/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
  187. package/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
  188. package/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  189. package/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  190. package/skills/web-design-guidelines/SKILL.md +0 -39
@@ -1,411 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- validate_skill.py — Kiểm tra tính hợp lệ của file SKILL.md
4
-
5
- Sử dụng:
6
- python validate_skill.py /path/to/SKILL.md
7
- python validate_skill.py /path/to/skill-folder/
8
-
9
- Script sẽ kiểm tra:
10
- 1. YAML frontmatter có hợp lệ không
11
- 2. Có đầy đủ các section bắt buộc không (Goal, Instructions)
12
- 3. Có Examples không (khuyến khích mạnh)
13
- 4. Có Constraints không (khuyến khích)
14
- 5. Description có đủ chi tiết không
15
- 6. Cấu trúc thư mục có chuẩn không
16
- """
17
-
18
- import sys
19
- import os
20
- import re
21
- from pathlib import Path
22
-
23
-
24
- # ============================================================
25
- # CONSTANTS
26
- # ============================================================
27
-
28
- REQUIRED_SECTIONS = ['goal', 'instructions']
29
- RECOMMENDED_SECTIONS = ['examples', 'constraints']
30
- MIN_DESCRIPTION_LENGTH = 30 # Ký tự tối thiểu cho description
31
- MIN_DESCRIPTION_WORDS = 5 # Từ tối thiểu cho description
32
- MAX_SKILL_NAME_LENGTH = 50 # Ký tự tối đa cho tên skill
33
- VALID_SUBFOLDERS = {'scripts', 'resources', 'examples'}
34
-
35
-
36
- # ============================================================
37
- # COLOR OUTPUT (Windows + Unix compatible)
38
- # ============================================================
39
-
40
- class Colors:
41
- """ANSI color codes cho terminal output."""
42
- PASS = '\033[92m' # Green
43
- FAIL = '\033[91m' # Red
44
- WARN = '\033[93m' # Yellow
45
- INFO = '\033[96m' # Cyan
46
- BOLD = '\033[1m'
47
- RESET = '\033[0m'
48
-
49
- @staticmethod
50
- def enable_windows():
51
- """Bật ANSI colors cho Windows terminal."""
52
- if os.name == 'nt':
53
- try:
54
- import ctypes
55
- kernel32 = ctypes.windll.kernel32
56
- kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
57
- except Exception:
58
- pass
59
-
60
-
61
- def print_result(status, message):
62
- """In kết quả kiểm tra với màu sắc."""
63
- if status == 'PASS':
64
- icon = f"{Colors.PASS}✅ PASS{Colors.RESET}"
65
- elif status == 'FAIL':
66
- icon = f"{Colors.FAIL}❌ FAIL{Colors.RESET}"
67
- elif status == 'WARN':
68
- icon = f"{Colors.WARN}⚠️ WARN{Colors.RESET}"
69
- else:
70
- icon = f"{Colors.INFO}ℹ️ INFO{Colors.RESET}"
71
-
72
- print(f" {icon} {message}")
73
-
74
-
75
- # ============================================================
76
- # YAML FRONTMATTER PARSER
77
- # ============================================================
78
-
79
- def parse_frontmatter(content):
80
- """
81
- Trích xuất YAML frontmatter từ nội dung SKILL.md.
82
-
83
- Returns:
84
- tuple: (frontmatter_dict, body_content) hoặc (None, content) nếu không có frontmatter
85
- """
86
- # Tìm YAML frontmatter (giữa 2 dấu ---)
87
- pattern = r'^---\s*\n(.*?)\n---\s*\n(.*)$'
88
- match = re.match(pattern, content, re.DOTALL)
89
-
90
- if not match:
91
- return None, content
92
-
93
- yaml_content = match.group(1)
94
- body = match.group(2)
95
-
96
- # Parse YAML đơn giản (hỗ trợ multi-line block scalar `|` và `>`)
97
- frontmatter = {}
98
- lines = yaml_content.strip().split('\n')
99
- i = 0
100
- while i < len(lines):
101
- line = lines[i]
102
- stripped = line.strip()
103
- if ':' in stripped and not stripped.startswith('#'):
104
- key, _, value = stripped.partition(':')
105
- key = key.strip()
106
- value = value.strip().strip('"').strip("'")
107
-
108
- # Xử lý multi-line block scalar (| hoặc >)
109
- if value in ('|', '>', '|+', '|-', '>+', '>-'):
110
- multi_lines = []
111
- i += 1
112
- while i < len(lines):
113
- next_line = lines[i]
114
- # Dòng tiếp theo phải có indent (bắt đầu bằng space/tab)
115
- if next_line and (next_line[0] == ' ' or next_line[0] == '\t'):
116
- multi_lines.append(next_line.strip())
117
- i += 1
118
- else:
119
- break
120
- value = ' '.join(multi_lines)
121
-
122
- frontmatter[key] = value
123
- i += 1
124
-
125
- return frontmatter, body
126
-
127
-
128
- def find_sections(body):
129
- """
130
- Tìm tất cả heading sections (# Level 1) trong body.
131
- Bỏ qua headings nằm trong fenced code blocks (``` ... ```).
132
-
133
- Returns:
134
- dict: {section_name_lowercase: section_content}
135
- """
136
- sections = {}
137
- current_section = None
138
- current_content = []
139
- in_code_block = False
140
-
141
- for line in body.split('\n'):
142
- stripped = line.strip()
143
-
144
- # Phát hiện bắt đầu/kết thúc code block
145
- if stripped.startswith('```'):
146
- in_code_block = not in_code_block
147
- current_content.append(line)
148
- continue
149
-
150
- # Bỏ qua headings trong code block
151
- if in_code_block:
152
- current_content.append(line)
153
- continue
154
-
155
- # Tìm heading level 1 (# Title)
156
- heading_match = re.match(r'^#\s+(.+)$', stripped)
157
- if heading_match:
158
- # Lưu section trước
159
- if current_section:
160
- sections[current_section] = '\n'.join(current_content)
161
- current_section = heading_match.group(1).strip().lower()
162
- current_content = []
163
- else:
164
- current_content.append(line)
165
-
166
- # Lưu section cuối cùng
167
- if current_section:
168
- sections[current_section] = '\n'.join(current_content)
169
-
170
- return sections
171
-
172
-
173
- def count_examples(body):
174
- """Đếm số ví dụ (heading ## Ví dụ hoặc ## Example). Bỏ qua code blocks."""
175
- # Xóa nội dung trong code blocks trước khi đếm
176
- clean_body = re.sub(r'```.*?```', '', body, flags=re.DOTALL)
177
- pattern = r'^##\s+(?:Ví dụ|Example)\s*\d*'
178
- return len(re.findall(pattern, clean_body, re.MULTILINE | re.IGNORECASE))
179
-
180
-
181
- def count_constraints(body):
182
- """Đếm số constraint (dòng bắt đầu bằng - KHÔNG ĐƯỢC hoặc - LUÔN LUÔN)."""
183
- pattern = r'^[-*]\s*(?:KHÔNG ĐƯỢC|LUÔN LUÔN|NEVER|ALWAYS|🚫|⚠️)'
184
- return len(re.findall(pattern, body, re.MULTILINE | re.IGNORECASE))
185
-
186
-
187
- # ============================================================
188
- # VALIDATORS
189
- # ============================================================
190
-
191
- def validate_frontmatter(frontmatter):
192
- """Kiểm tra YAML frontmatter."""
193
- results = []
194
-
195
- if frontmatter is None:
196
- results.append(('FAIL', 'Không tìm thấy YAML frontmatter (--- đầu và cuối)'))
197
- return results, False
198
-
199
- results.append(('PASS', 'YAML frontmatter hợp lệ'))
200
-
201
- # Check description (BẮT BUỘC)
202
- desc = frontmatter.get('description', '')
203
- if not desc:
204
- results.append(('FAIL', 'Thiếu trường `description` — Đây là phần QUAN TRỌNG NHẤT'))
205
- elif len(desc) < MIN_DESCRIPTION_LENGTH:
206
- results.append(('WARN', f'Description quá ngắn ({len(desc)} ký tự) — Nên ≥{MIN_DESCRIPTION_LENGTH} ký tự'))
207
- elif len(desc.split()) < MIN_DESCRIPTION_WORDS:
208
- results.append(('WARN', f'Description quá ít từ ({len(desc.split())} từ) — Nên ≥{MIN_DESCRIPTION_WORDS} từ'))
209
- else:
210
- results.append(('PASS', f'Description đầy đủ ({len(desc)} ký tự, {len(desc.split())} từ)'))
211
-
212
- # Check name (TÙY CHỌN)
213
- name = frontmatter.get('name', '')
214
- if name:
215
- if ' ' in name or any(c.isupper() for c in name):
216
- results.append(('WARN', f'Tên skill `{name}` nên dùng kebab-case (vd: my-skill-name)'))
217
- elif len(name) > MAX_SKILL_NAME_LENGTH:
218
- results.append(('WARN', f'Tên skill quá dài ({len(name)} ký tự) — Nên ≤{MAX_SKILL_NAME_LENGTH}'))
219
- else:
220
- results.append(('PASS', f'Tên skill: `{name}` (hợp lệ)'))
221
- else:
222
- results.append(('INFO', 'Không có trường `name` — AI sẽ dùng tên thư mục'))
223
-
224
- return results, True
225
-
226
-
227
- def validate_sections(sections, body):
228
- """Kiểm tra các sections bắt buộc và khuyến khích."""
229
- results = []
230
-
231
- # Check required sections
232
- for section in REQUIRED_SECTIONS:
233
- found = any(section in key for key in sections.keys())
234
- if found:
235
- results.append(('PASS', f'Có section `# {section.title()}`'))
236
- else:
237
- results.append(('FAIL', f'Thiếu section bắt buộc `# {section.title()}`'))
238
-
239
- # Check recommended sections
240
- for section in RECOMMENDED_SECTIONS:
241
- found = any(section in key for key in sections.keys())
242
- if found:
243
- results.append(('PASS', f'Có section `# {section.title()}`'))
244
- else:
245
- results.append(('WARN', f'Thiếu section khuyến khích `# {section.title()}`'))
246
-
247
- # Check examples count
248
- example_count = count_examples(body)
249
- if example_count >= 2:
250
- results.append(('PASS', f'Có {example_count} ví dụ (đạt chuẩn ≥2)'))
251
- elif example_count == 1:
252
- results.append(('WARN', f'Chỉ có {example_count} ví dụ — Nên có ≥2 ví dụ để giảm hallucination'))
253
- else:
254
- results.append(('WARN', 'Không tìm thấy ví dụ nào — Rất khuyến khích thêm ≥2 ví dụ'))
255
-
256
- # Check constraints count
257
- constraint_count = count_constraints(body)
258
- if constraint_count >= 1:
259
- results.append(('PASS', f'Có {constraint_count} constraint(s)'))
260
- else:
261
- results.append(('WARN', 'Không tìm thấy constraint nào — Nên có ít nhất 1 quy tắc "KHÔNG ĐƯỢC"'))
262
-
263
- return results
264
-
265
-
266
- def validate_directory(skill_dir):
267
- """Kiểm tra cấu trúc thư mục skill."""
268
- results = []
269
- skill_path = Path(skill_dir)
270
-
271
- # Check SKILL.md exists
272
- skill_md = skill_path / 'SKILL.md'
273
- if skill_md.exists():
274
- results.append(('PASS', f'File `SKILL.md` tồn tại ({skill_md.stat().st_size} bytes)'))
275
- else:
276
- results.append(('FAIL', 'Không tìm thấy `SKILL.md` trong thư mục'))
277
- return results, None
278
-
279
- # Check subfolders
280
- for item in skill_path.iterdir():
281
- if item.is_dir():
282
- folder_name = item.name
283
- if folder_name in VALID_SUBFOLDERS:
284
- file_count = len(list(item.rglob('*')))
285
- results.append(('PASS', f'Thư mục `{folder_name}/` ({file_count} items)'))
286
- elif folder_name.startswith('.'):
287
- continue # Bỏ qua hidden folders
288
- else:
289
- results.append(('WARN', f'Thư mục `{folder_name}/` không phải chuẩn (scripts/resources/examples)'))
290
-
291
- return results, skill_md
292
-
293
-
294
- # ============================================================
295
- # MAIN
296
- # ============================================================
297
-
298
- def validate_skill(target_path):
299
- """Chạy toàn bộ kiểm tra cho skill."""
300
- Colors.enable_windows()
301
-
302
- target = Path(target_path)
303
- all_results = []
304
-
305
- print(f"\n{Colors.BOLD}{'='*60}{Colors.RESET}")
306
- print(f"{Colors.BOLD}🔍 SKILL VALIDATOR — Kiểm tra chất lượng AI Skill{Colors.RESET}")
307
- print(f"{Colors.BOLD}{'='*60}{Colors.RESET}")
308
- print(f"{Colors.INFO}📁 Target: {target.absolute()}{Colors.RESET}\n")
309
-
310
- # ---- Phần 1: Kiểm tra thư mục (nếu là folder) ----
311
- skill_md_path = None
312
-
313
- if target.is_dir():
314
- print(f"{Colors.BOLD}📂 Kiểm tra cấu trúc thư mục:{Colors.RESET}")
315
- dir_results, skill_md_path = validate_directory(target)
316
- all_results.extend(dir_results)
317
- for status, msg in dir_results:
318
- print_result(status, msg)
319
- print()
320
-
321
- if skill_md_path is None:
322
- print(f"\n{Colors.FAIL}💀 KHÔNG THỂ TIẾP TỤC — Thiếu SKILL.md{Colors.RESET}\n")
323
- return False
324
- elif target.is_file() and target.name == 'SKILL.md':
325
- skill_md_path = target
326
- else:
327
- print(f"{Colors.FAIL}❌ Target phải là thư mục skill hoặc file SKILL.md{Colors.RESET}")
328
- return False
329
-
330
- # ---- Phần 2: Đọc và parse SKILL.md ----
331
- try:
332
- content = skill_md_path.read_text(encoding='utf-8')
333
- except UnicodeDecodeError:
334
- content = skill_md_path.read_text(encoding='utf-8', errors='ignore')
335
-
336
- frontmatter, body = parse_frontmatter(content)
337
- sections = find_sections(body)
338
-
339
- # ---- Phần 3: Kiểm tra frontmatter ----
340
- print(f"{Colors.BOLD}📝 Kiểm tra YAML Frontmatter:{Colors.RESET}")
341
- fm_results, fm_valid = validate_frontmatter(frontmatter)
342
- all_results.extend(fm_results)
343
- for status, msg in fm_results:
344
- print_result(status, msg)
345
- print()
346
-
347
- # ---- Phần 4: Kiểm tra sections ----
348
- print(f"{Colors.BOLD}📋 Kiểm tra nội dung Sections:{Colors.RESET}")
349
- sec_results = validate_sections(sections, body)
350
- all_results.extend(sec_results)
351
- for status, msg in sec_results:
352
- print_result(status, msg)
353
- print()
354
-
355
- # ---- Phần 5: Thống kê ----
356
- total_lines = len(content.split('\n'))
357
- total_words = len(content.split())
358
-
359
- print(f"{Colors.BOLD}📊 Thống kê:{Colors.RESET}")
360
- print_result('INFO', f'Tổng: {total_lines} dòng, {total_words} từ, {len(content)} bytes')
361
- print_result('INFO', f'Sections tìm thấy: {", ".join(sections.keys()) if sections else "(không có)"}')
362
- print()
363
-
364
- # ---- Phần 6: Tổng kết ----
365
- fails = sum(1 for s, _ in all_results if s == 'FAIL')
366
- warns = sum(1 for s, _ in all_results if s == 'WARN')
367
- passes = sum(1 for s, _ in all_results if s == 'PASS')
368
-
369
- print(f"{Colors.BOLD}{'='*60}{Colors.RESET}")
370
- print(f"{Colors.BOLD}📋 KẾT QUẢ:{Colors.RESET}")
371
- print(f" {Colors.PASS}✅ PASS: {passes}{Colors.RESET}")
372
- print(f" {Colors.WARN}⚠️ WARN: {warns}{Colors.RESET}")
373
- print(f" {Colors.FAIL}❌ FAIL: {fails}{Colors.RESET}")
374
-
375
- if fails == 0 and warns == 0:
376
- print(f"\n {Colors.PASS}{Colors.BOLD}🎉 TUYỆT VỜI! Skill đạt chuẩn hoàn hảo!{Colors.RESET}")
377
- grade = 'A+'
378
- elif fails == 0 and warns <= 2:
379
- print(f"\n {Colors.PASS}{Colors.BOLD}👍 TỐT! Skill hợp lệ, có thể cải thiện thêm.{Colors.RESET}")
380
- grade = 'A'
381
- elif fails == 0:
382
- print(f"\n {Colors.WARN}{Colors.BOLD}⚠️ ĐẠT! Nhưng nên sửa các cảnh báo.{Colors.RESET}")
383
- grade = 'B'
384
- elif fails <= 2:
385
- print(f"\n {Colors.FAIL}{Colors.BOLD}❌ CHƯA ĐẠT! Cần sửa {fails} lỗi.{Colors.RESET}")
386
- grade = 'C'
387
- else:
388
- print(f"\n {Colors.FAIL}{Colors.BOLD}💀 KHÔNG ĐẠT! Cần sửa {fails} lỗi nghiêm trọng.{Colors.RESET}")
389
- grade = 'F'
390
-
391
- print(f"\n {Colors.BOLD}📊 Grade: {grade}{Colors.RESET}")
392
- print(f"{Colors.BOLD}{'='*60}{Colors.RESET}\n")
393
-
394
- return fails == 0
395
-
396
-
397
- if __name__ == '__main__':
398
- if len(sys.argv) < 2:
399
- print("Sử dụng: python validate_skill.py <path-to-SKILL.md-or-skill-folder>")
400
- print("Ví dụ: python validate_skill.py ./my-skill/")
401
- print(" python validate_skill.py ./my-skill/SKILL.md")
402
- sys.exit(1)
403
-
404
- target = sys.argv[1]
405
-
406
- if not os.path.exists(target):
407
- print(f"❌ Không tìm thấy: {target}")
408
- sys.exit(1)
409
-
410
- success = validate_skill(target)
411
- sys.exit(0 if success else 1)
@@ -1,229 +0,0 @@
1
- ---
2
- name: tailwind-mastery
3
- description: 'Master Tailwind CSS utilities, responsive design, and accessibility patterns. Use when the user mentions "Tailwind", "Tailwind CSS", "utility-first", "responsive design", "dark mode", "focus-visible", "motion-reduce", or "Tailwind v4". Covers utility patterns, layout, responsive design, components, accessibility, and performance. For React styling, see react-mastery. For design systems, see refactoring-ui.'
4
- license: MIT
5
- metadata:
6
- author: todyle
7
- version: "1.0.0"
8
- ---
9
-
10
- # Tailwind CSS Mastery Framework
11
-
12
- A comprehensive guide to building production UIs with Tailwind CSS utilities, responsive patterns, accessibility, and performance optimization. Apply these principles when styling web applications, building component libraries, implementing dark mode, or optimizing CSS output.
13
-
14
- ## Core Principle
15
-
16
- **Utility-first CSS means composing designs directly in HTML with small, single-purpose classes.** Instead of writing custom CSS for every component, you combine utilities (`flex`, `items-center`, `p-4`, `text-lg`) to build designs. This eliminates naming fatigue, CSS specificity wars, and dead CSS. Every class you see describes exactly what it does.
17
-
18
- **The foundation:** Tailwind works because most CSS is repeated — the same spacing, colors, and typography patterns appear throughout an application. Utilities express these patterns directly. The build tool strips unused classes, resulting in tiny production CSS. The key is working within Tailwind's design system (spacing scale, color palette, breakpoints) rather than escaping it with arbitrary values.
19
-
20
- ## Scoring
21
-
22
- **Goal: 10/10.** When reviewing Tailwind code, rate 0-10:
23
-
24
- - **9-10:** Mobile-first responsive, dark mode, focus-visible, motion-reduce, semantic color naming, consistent spacing scale
25
- - **7-8:** Good utility usage with minor issues (arbitrary values for scale values, missing dark mode, inconsistent spacing)
26
- - **5-6:** Working styles but overusing @apply, arbitrary values abundant, no responsive design
27
- - **3-4:** Tailwind as CSS-in-HTML (every value arbitrary), no dark mode, no accessibility
28
- - **1-2:** Fighting Tailwind with custom CSS, important! everywhere, no design system
29
-
30
- ## The Tailwind Mastery Framework
31
-
32
- Six disciplines for production Tailwind CSS:
33
-
34
- ### 1. Utility Patterns & Design System
35
-
36
- **Core concept:** Use Tailwind's design tokens (spacing scale, color palette, font sizes) instead of arbitrary values. The spacing scale (4px increments: `p-1`=4px, `p-2`=8px, `p-4`=16px) creates visual consistency. Extend the design system via `tailwind.config.js` for brand colors, not with arbitrary `[]` values.
37
-
38
- **Why it works:** Constraints breed consistency. When everyone uses `gap-4` instead of `gap-[15px]`, spacing is uniform across the entire application. The predefined scale means fewer design decisions and faster development. Custom theme values (`bg-primary`, `text-success`) encode brand semantics.
39
-
40
- **Key insights:**
41
- - Spacing scale: `p-1`=4px, `p-2`=8px, `p-4`=16px, `p-6`=24px, `p-8`=32px
42
- - Use scale values over arbitrary: `gap-6` not `gap-[23px]`
43
- - Color opacity: `bg-black/50` (50% opacity) instead of separate `opacity-50`
44
- - `space-y-4` for vertical lists — adds margin between children
45
- - `size-6` shorthand for equal width+height (Tailwind v4)
46
- - `shrink-0` shorthand (v4) instead of `flex-shrink-0`
47
- - Extend theme for brand colors: `bg-primary`, `text-cta`, `border-success`
48
- - `bg-linear-to-r` (v4) replaces `bg-gradient-to-r`
49
-
50
- **Code applications:**
51
-
52
- | Context | Pattern | Example |
53
- |---------|---------|---------|
54
- | **Spacing** | Scale values | `p-4 m-6 gap-8` |
55
- | **Color opacity** | Slash syntax | `bg-black/50 text-white/80` |
56
- | **List spacing** | space-y | `<div class="space-y-4">` |
57
- | **Brand color** | Theme extend | `bg-primary text-on-primary` |
58
- | **Square element** | size utility | `size-8` (= `h-8 w-8`) |
59
- | **Gradient** | bg-linear (v4) | `bg-linear-to-r from-blue-500 to-purple-500` |
60
-
61
- ### 2. Layout
62
-
63
- **Core concept:** Container with `max-w-7xl mx-auto` for content width. `flex` for one-dimensional, `grid` for two-dimensional layouts. Responsive padding `px-4 md:px-6 lg:px-8`. Container queries `@container` for component-level responsiveness.
64
-
65
- **Why it works:** `max-w-7xl mx-auto` prevents content from stretching to unreadable widths on large screens. `gap-*` replaces manual margins on grid/flex children, simplifying layout code. Container queries enable components to respond to their container size rather than the viewport — essential for reusable components.
66
-
67
- **Key insights:**
68
- - `max-w-7xl mx-auto px-4` for main content container
69
- - `flex items-center justify-between` — most common header pattern
70
- - `grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6` for responsive grid
71
- - `gap-*` on flex/grid containers, not margins on children
72
- - Responsive padding: `px-4 sm:px-6 lg:px-8`
73
- - `@container` + `@lg:grid-cols-2` for component-level responsive (v3.2+)
74
- - Negative margins sparingly: `-mt-8` for intentional overlapping effects
75
-
76
- **Code applications:**
77
-
78
- | Context | Pattern | Example |
79
- |---------|---------|---------|
80
- | **Container** | max-w + padding | `<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">` |
81
- | **Flex row** | items-center | `<nav class="flex items-center justify-between h-16">` |
82
- | **Grid** | Responsive cols | `<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">` |
83
- | **Container query** | @container | `<div class="@container"><div class="@lg:grid-cols-2">` |
84
-
85
- ### 3. Responsive Design
86
-
87
- **Core concept:** Mobile-first — write base styles for mobile, add breakpoints for larger screens via `sm:`, `md:`, `lg:`, `xl:`, `2xl:` prefixes. Test at all breakpoints: 320, 375, 768, 1024, 1280, 1536px. Use `hidden md:block` for visibility control.
88
-
89
- **Why it works:** Mobile-first ensures the smallest, most constrained screens get attention first. Adding complexity for larger screens is natural — hiding sidebar on mobile, showing it on desktop. This approach also results in smaller CSS because mobile styles don't need breakpoint prefixes.
90
-
91
- **Key insights:**
92
- - Base styles = mobile. Breakpoints add desktop enhancements
93
- - `text-sm md:text-base lg:text-lg` — progressive text sizing
94
- - `hidden md:flex` — hide on mobile, show on desktop
95
- - `flex-col md:flex-row` — stack on mobile, row on desktop
96
- - Test at 320px (smallest iPhone SE) — don't ignore small screens
97
- - `aspect-video` with `object-cover` for responsive media
98
- - `srcset` with `sizes` attribute for responsive images (HTML, not Tailwind)
99
-
100
- **Code applications:**
101
-
102
- | Context | Pattern | Example |
103
- |---------|---------|---------|
104
- | **Mobile-first** | Base + breakpoint | `<h1 class="text-2xl md:text-4xl lg:text-5xl">` |
105
- | **Show/hide** | hidden + display | `<nav class="hidden md:flex">` (mobile menu alternative) |
106
- | **Stack → row** | Direction change | `<div class="flex flex-col md:flex-row gap-4">` |
107
- | **Responsive image** | aspect + object | `<img class="aspect-video object-cover w-full rounded-xl">` |
108
- | **Responsive padding** | Breakpoint padding | `<main class="px-4 sm:px-6 lg:px-8">` |
109
-
110
- ### 4. Components
111
-
112
- **Core concept:** Buttons need consistent sizing (`px-4 py-2`), minimum touch targets on mobile (`min-h-[44px]`), loading states, and proper icon button labels. Cards use `rounded-lg shadow-md` with hover feedback. Forms need visible focus indicators (`focus:ring-2`), disabled states, and keyboard accessibility.
113
-
114
- **Why it works:** Consistency in component sizing creates visual rhythm. Touch targets of 44px minimum (Apple HIG standard) prevent frustrating tap misses on mobile. Focus indicators are essential for keyboard navigation and WCAG compliance. Interactive elements must provide feedback — hover, focus, active, disabled states.
115
-
116
- **Key insights:**
117
- - Buttons: `px-4 py-2 rounded-lg font-medium transition-colors`
118
- - Touch targets: `min-h-[44px] min-w-[44px]` on all interactive mobile elements
119
- - Loading button: `disabled + opacity-50 + spinner icon`
120
- - Cards: `rounded-2xl shadow-lg p-6 hover:shadow-xl transition-shadow`
121
- - Inputs: `h-10 w-full px-3 rounded-md border focus:ring-2 focus:ring-blue-500`
122
- - Disabled: `disabled:opacity-50 disabled:cursor-not-allowed`
123
- - Icon buttons: always include `aria-label`
124
-
125
- **Code applications:**
126
-
127
- | Context | Pattern | Example |
128
- |---------|---------|---------|
129
- | **Button** | Standard | `<button class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors">` |
130
- | **Touch target** | Mobile minimum | `<button class="min-h-[44px] min-w-[44px]">` |
131
- | **Card** | Hover feedback | `<div class="rounded-2xl shadow-lg p-6 hover:shadow-xl transition-shadow">` |
132
- | **Input** | Focus ring | `<input class="h-10 px-3 rounded-md border focus:ring-2 focus:ring-blue-500">` |
133
- | **Disabled** | Opacity + cursor | `<button disabled class="disabled:opacity-50 disabled:cursor-not-allowed">` |
134
- | **Icon button** | aria-label | `<button aria-label="Close"><XIcon class="size-5"/></button>` |
135
-
136
- ### 5. Accessibility
137
-
138
- **Core concept:** `sr-only` for screen reader text, `focus-visible:ring-2` for keyboard-only focus indicators, `motion-reduce:animate-none` for motion sensitivity, semantic HTML always. Accessibility is not optional — it's a legal requirement in many jurisdictions.
139
-
140
- **Why it works:** `focus-visible` shows focus rings only for keyboard users (not mouse clicks), improving both aesthetics and accessibility. `motion-reduce` respects OS-level reduced motion preferences — essential for users with vestibular disorders. `sr-only` provides context to screen readers without affecting visual design.
141
-
142
- **Key insights:**
143
- - `sr-only` for text visible only to screen readers
144
- - `focus-visible:ring-2` instead of `focus:ring-2` — keyboard-only focus
145
- - `motion-reduce:animate-none` respects prefers-reduced-motion
146
- - `motion-reduce:transition-none` for transition-heavy components
147
- - Never `outline-none` without a replacement focus indicator
148
- - Always `aria-label` on icon-only buttons
149
- - Dark mode: `dark:bg-gray-900 dark:text-gray-100` — ensure sufficient contrast
150
- - SVG explicit dimensions: `<svg class="size-6" width="24" height="24">` to prevent layout shift
151
-
152
- **Code applications:**
153
-
154
- | Context | Pattern | Example |
155
- |---------|---------|---------|
156
- | **Screen reader** | sr-only | `<span class="sr-only">Close menu</span>` |
157
- | **Keyboard focus** | focus-visible | `<button class="focus-visible:ring-2 focus-visible:ring-blue-500">` |
158
- | **Reduced motion** | motion-reduce | `<div class="animate-pulse motion-reduce:animate-none">` |
159
- | **Dark mode** | dark: prefix | `<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">` |
160
- | **Icon a11y** | aria-label | `<button aria-label="Delete item"><TrashIcon class="size-5"/></button>` |
161
- | **SVG dims** | Explicit w/h | `<svg class="size-6" width="24" height="24">` |
162
-
163
- ### 6. Performance & Configuration
164
-
165
- **Core concept:** Configure `content` paths correctly so Tailwind can tree-shake unused classes. Avoid overusing `@apply` — it defeats the purpose of utility-first CSS. Use JIT mode (default in v3+) for development performance. Custom utilities in theme config for repeated one-off values.
166
-
167
- **Why it works:** Tailwind's production CSS is tiny because it only includes classes actually used in your source files. Incorrect `content` configuration results in either missing styles (too narrow) or bloated CSS (too broad). `@apply` creates abstraction layers that Tailwind's utility-first approach was designed to eliminate.
168
-
169
- **Key insights:**
170
- - `content: ['./src/**/*.{js,ts,jsx,tsx}']` — must cover all template files
171
- - `@apply` sparingly — prefer direct utilities in HTML/JSX
172
- - Custom utilities in `tailwind.config.js` for repeated arbitrary values
173
- - `@tailwindcss/forms` for consistent form element reset
174
- - `@tailwindcss/typography` (`prose`) for markdown/CMS content
175
- - Group and Peer for parent/sibling state: `group-hover:text-blue-500`
176
- - `peer-checked:bg-blue-100` for checkbox/radio state styling
177
-
178
- **Code applications:**
179
-
180
- | Context | Pattern | Example |
181
- |---------|---------|---------|
182
- | **Content config** | Glob patterns | `content: ['./src/**/*.{js,ts,jsx,tsx,html}']` |
183
- | **Custom utility** | Theme extend | `extend: { boxShadow: { card: '0 4px 20px rgba(0,0,0,.08)' } }` |
184
- | **Plugin** | Official | `plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')]` |
185
- | **Group hover** | Parent state | `<div class="group"><span class="group-hover:text-blue-500">` |
186
- | **Peer** | Sibling state | `<input class="peer"><label class="peer-checked:font-bold">` |
187
- | **Prose** | Typography | `<article class="prose prose-lg max-w-none dark:prose-invert">` |
188
-
189
- ## Common Mistakes
190
-
191
- | Mistake | Why It Fails | Fix |
192
- |---------|-------------|-----|
193
- | **Arbitrary values for scale values** | Inconsistent spacing/sizing | Use `p-4` not `p-[15px]` |
194
- | **Heavy @apply usage** | Creates CSS abstractions that defeat utility-first | Use utilities directly in HTML |
195
- | **No dark mode** | Poor UX in low-light, not respecting OS preference | Add `dark:` variants |
196
- | **outline-none without replacement** | Keyboard users can't see focus | `focus-visible:ring-2` |
197
- | **No motion-reduce** | Harms vestibular disorder users | `motion-reduce:animate-none` |
198
- | **Small touch targets** | Frustrating mobile experience | `min-h-[44px]` minimum |
199
- | **Missing content paths** | Styles missing in production | Verify all template file paths |
200
- | **Desktop-first approach** | Complex mobile overrides | Start with mobile, add `md:` `lg:` |
201
- | **bg-gradient-to in v4** | Deprecated syntax | Use `bg-linear-to-r` in Tailwind v4 |
202
- | **SVGs without explicit dimensions** | Layout shift before CSS loads | Add `width` and `height` attributes |
203
-
204
- ## Quick Diagnostic
205
-
206
- | Question | If No | Action |
207
- |----------|-------|--------|
208
- | Using Tailwind's spacing scale? | Inconsistent spacing | Replace arbitrary values with scale tokens |
209
- | Mobile-first responsive? | Complex overrides | Start with mobile base, add breakpoints |
210
- | Dark mode implemented? | Missing OS preference respect | Add `dark:` variants for all colors |
211
- | Focus indicators visible? | Keyboard a11y broken | Add `focus-visible:ring-2` |
212
- | Motion preferences respected? | A11y violation | Add `motion-reduce:` variants |
213
- | Touch targets ≥44px? | Mobile tap frustration | Add `min-h-[44px]` |
214
- | Content paths correct? | Missing production styles | Audit tailwind.config.js content |
215
- | Using semantic colors? | Hard to rebrand | Move to `bg-primary` theme tokens |
216
- | Icon buttons labeled? | Screen reader fails | Add `aria-label` to all icon buttons |
217
- | SVGs have explicit dimensions? | Layout shift | Add `width` and `height` attributes |
218
-
219
- ## Further Reading
220
-
221
- - [Tailwind CSS Documentation](https://tailwindcss.com/docs) — Official reference
222
- - [Tailwind CSS v4 Migration](https://tailwindcss.com/docs/upgrade-guide) — v3 to v4 changes
223
- - [Refactoring UI](https://www.refactoringui.com/) — Design principles from Tailwind creators
224
- - [@tailwindcss/typography](https://tailwindcss.com/docs/typography-plugin) — Prose styling
225
- - [Heroicons](https://heroicons.com/) — SVG icons from Tailwind Labs
226
-
227
- ## About
228
-
229
- This skill synthesizes patterns from Adam Wathan (Tailwind creator), Steve Schoger (Refactoring UI), and the Tailwind CSS community. For visual design principles, see refactoring-ui. For top-tier web design, see top-design. For React integration, see react-mastery.