@trishchuk/coolors-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +39 -0
- package/.env +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +73 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
- package/.github/pull_request_template.md +97 -0
- package/.github/workflows/ci.yml +127 -0
- package/.github/workflows/deploy-docs.yml +56 -0
- package/.github/workflows/release.yml +99 -0
- package/.mcp.json +12 -0
- package/.prettierignore +1 -0
- package/CLAUDE.md +201 -0
- package/DOCUMENTATION.md +274 -0
- package/GEMINI.md +54 -0
- package/LICENSE +21 -0
- package/README.md +401 -0
- package/demo/content_based_color.png +0 -0
- package/demo/music-player.html +621 -0
- package/demo/podcast-player.html +903 -0
- package/dist/bin/coolors-mcp.d.ts +1 -0
- package/dist/bin/coolors-mcp.js +154 -0
- package/dist/bin/coolors-mcp.js.map +1 -0
- package/dist/bin/server.d.ts +1 -0
- package/dist/bin/server.js +3292 -0
- package/dist/bin/server.js.map +1 -0
- package/dist/chunk-IQ7NN26V.js +114 -0
- package/dist/chunk-IQ7NN26V.js.map +1 -0
- package/dist/chunk-P3ARRKLS.js +1214 -0
- package/dist/chunk-P3ARRKLS.js.map +1 -0
- package/dist/color/index.d.ts +716 -0
- package/dist/color/index.js +153 -0
- package/dist/color/index.js.map +1 -0
- package/dist/coolors-mcp.d.ts +136 -0
- package/dist/coolors-mcp.js +7 -0
- package/dist/coolors-mcp.js.map +1 -0
- package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
- package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
- package/docs/.vitepress/cache/deps/_metadata.json +127 -0
- package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
- package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
- package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +12683 -0
- package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +7 -0
- package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +9719 -0
- package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +7 -0
- package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
- package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
- package/docs/.vitepress/cache/deps/cytoscape.js +30278 -0
- package/docs/.vitepress/cache/deps/cytoscape.js.map +7 -0
- package/docs/.vitepress/cache/deps/dayjs.js +285 -0
- package/docs/.vitepress/cache/deps/dayjs.js.map +7 -0
- package/docs/.vitepress/cache/deps/debug.js +468 -0
- package/docs/.vitepress/cache/deps/debug.js.map +7 -0
- package/docs/.vitepress/cache/deps/package.json +3 -0
- package/docs/.vitepress/cache/deps/prismjs.js +1466 -0
- package/docs/.vitepress/cache/deps/prismjs.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +228 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +142 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +27 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +65 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +53 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +73 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1146 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
- package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1814 -0
- package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
- package/docs/.vitepress/cache/deps/vue.js +344 -0
- package/docs/.vitepress/cache/deps/vue.js.map +7 -0
- package/docs/.vitepress/components/ClientGrid.vue +125 -0
- package/docs/.vitepress/components/CodeBlock.vue +231 -0
- package/docs/.vitepress/components/ConfigModal.vue +477 -0
- package/docs/.vitepress/components/DiagramModal.vue +528 -0
- package/docs/.vitepress/components/TroubleshootingModal.vue +472 -0
- package/docs/.vitepress/config.js +162 -0
- package/docs/.vitepress/theme/FundingLayout.vue +251 -0
- package/docs/.vitepress/theme/Layout.vue +134 -0
- package/docs/.vitepress/theme/components/AdBanner.vue +317 -0
- package/docs/.vitepress/theme/components/AdPlaceholder.vue +78 -0
- package/docs/.vitepress/theme/components/FundingEffects.vue +322 -0
- package/docs/.vitepress/theme/components/FundingHero.vue +345 -0
- package/docs/.vitepress/theme/components/SupportSection.vue +511 -0
- package/docs/.vitepress/theme/custom-app.css +339 -0
- package/docs/.vitepress/theme/custom.css +699 -0
- package/docs/.vitepress/theme/index.js +25 -0
- package/docs/README.md +198 -0
- package/docs/concepts/accessibility.md +473 -0
- package/docs/concepts/color-spaces.md +222 -0
- package/docs/concepts/distance-metrics.md +384 -0
- package/docs/concepts/hct.md +261 -0
- package/docs/concepts/image-analysis.md +396 -0
- package/docs/concepts/material-design.md +306 -0
- package/docs/concepts/theme-matching.md +399 -0
- package/docs/examples/basic-colors.md +490 -0
- package/docs/examples/creating-themes.md +898 -0
- package/docs/examples/css-refactoring.md +824 -0
- package/docs/examples/image-extraction.md +882 -0
- package/docs/getting-started.md +366 -0
- package/docs/index.md +190 -0
- package/docs/installation.md +157 -0
- package/docs/tools/README.md +234 -0
- package/docs/tools/accessibility.md +614 -0
- package/docs/tools/color-operations.md +374 -0
- package/docs/tools/image-extraction.md +624 -0
- package/docs/tools/material-design.md +347 -0
- package/docs/tools/theme-matching.md +552 -0
- package/eslint.config.ts +14 -0
- package/examples/theme-matching.md +113 -0
- package/jsr.json +7 -0
- package/mcp-config.json +8 -0
- package/note.md +35 -0
- package/package.json +122 -0
- package/research_results.md +53 -0
- package/src/bin/coolors-mcp.ts +194 -0
- package/src/bin/server.ts +61 -0
- package/src/color/__tests__/conversions-argb.test.ts +198 -0
- package/src/color/__tests__/extract-colors.test.ts +360 -0
- package/src/color/__tests__/image-utils.test.ts +242 -0
- package/src/color/__tests__/reference-colors.test.ts +278 -0
- package/src/color/__tests__/round-trip.test.ts +197 -0
- package/src/color/conversions.test.ts +402 -0
- package/src/color/conversions.ts +393 -0
- package/src/color/dislike/__tests__/dislike-analyzer.test.ts +248 -0
- package/src/color/dislike/dislike-analyzer.ts +114 -0
- package/src/color/extract-colors.ts +228 -0
- package/src/color/hct/__tests__/hct-class.test.ts +232 -0
- package/src/color/hct/harmonization.ts +204 -0
- package/src/color/hct/hct-class.ts +109 -0
- package/src/color/hct/hct-solver.ts +168 -0
- package/src/color/hct/index.ts +39 -0
- package/src/color/hct/tonal-palette.ts +211 -0
- package/src/color/hct/types.ts +88 -0
- package/src/color/image-utils.ts +79 -0
- package/src/color/index.ts +87 -0
- package/src/color/material-theme.ts +157 -0
- package/src/color/metrics.test.ts +276 -0
- package/src/color/metrics.ts +281 -0
- package/src/color/quantize/__tests__/quantizer_celebi.test.ts +195 -0
- package/src/color/quantize/lab_point_provider.ts +55 -0
- package/src/color/quantize/point_provider.ts +27 -0
- package/src/color/quantize/quantizer_celebi.ts +51 -0
- package/src/color/quantize/quantizer_celebi_test.ts +71 -0
- package/src/color/quantize/quantizer_map.ts +47 -0
- package/src/color/quantize/quantizer_wsmeans.ts +232 -0
- package/src/color/quantize/quantizer_wu.ts +472 -0
- package/src/color/score/__tests__/score.test.ts +224 -0
- package/src/color/score/score.ts +175 -0
- package/src/color/types.ts +151 -0
- package/src/color/utils/color_utils.ts +292 -0
- package/src/color/utils/math_utils.ts +145 -0
- package/src/color/utils.test.ts +403 -0
- package/src/color/utils.ts +315 -0
- package/src/constants.ts +5 -0
- package/src/coolors-mcp.ts +37 -0
- package/src/examples/addition.ts +333 -0
- package/src/examples/color-demo.ts +125 -0
- package/src/examples/custom-logger.ts +201 -0
- package/src/examples/oauth-server.ts +113 -0
- package/src/examples/session-context.ts +269 -0
- package/src/session.ts +116 -0
- package/src/theme/__tests__/matcher.test.ts +180 -0
- package/src/theme/__tests__/parser.test.ts +148 -0
- package/src/theme/__tests__/refactor.test.ts +224 -0
- package/src/theme/index.ts +34 -0
- package/src/theme/matcher.ts +395 -0
- package/src/theme/parser.ts +392 -0
- package/src/theme/refactor.ts +360 -0
- package/src/theme/types.ts +152 -0
- package/src/tools/__tests__/gradient-generator.test.ts +206 -0
- package/src/tools/__tests__/palette-with-locks.test.ts +109 -0
- package/src/tools/color-conversion.tool.ts +54 -0
- package/src/tools/color-distance.tool.ts +41 -0
- package/src/tools/colors.ts +31 -0
- package/src/tools/contrast-checker.tool.ts +37 -0
- package/src/tools/dislike-analyzer.tool.ts +247 -0
- package/src/tools/gradient-generator.tool.ts +250 -0
- package/src/tools/image-extraction.tools.ts +289 -0
- package/src/tools/index.ts +39 -0
- package/src/tools/material-theme.tools.ts +250 -0
- package/src/tools/palette-generator.tool.ts +135 -0
- package/src/tools/palette-with-locks.tool.ts +221 -0
- package/src/tools/registry.ts +142 -0
- package/src/tools/simple-tools.ts +37 -0
- package/src/tools/theme-matching.tools.ts +334 -0
- package/src/types.ts +182 -0
- package/src/utils.ts +22 -0
- package/tsconfig.json +8 -0
- package/vitest.config.js +15 -0
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
# CSS Refactoring Examples
|
|
2
|
+
|
|
3
|
+
Learn how to modernize your CSS by replacing hardcoded colors with theme variables using Coolors MCP's intelligent matching and refactoring tools.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Simple Color Replacement
|
|
8
|
+
|
|
9
|
+
Replace a single hardcoded color with a theme variable:
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
// Find matching theme variable
|
|
13
|
+
"What theme variable matches #6366f1?"
|
|
14
|
+
|
|
15
|
+
// With theme CSS
|
|
16
|
+
const theme = `
|
|
17
|
+
:root {
|
|
18
|
+
--color-primary-500: #6366f1;
|
|
19
|
+
--color-primary-600: #4f46e5;
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
// Result: --color-primary-500 (100% confidence)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Automatic CSS Refactoring
|
|
27
|
+
|
|
28
|
+
Refactor an entire stylesheet:
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
"Refactor this CSS to use theme variables:
|
|
32
|
+
.button {
|
|
33
|
+
background: #6366f1;
|
|
34
|
+
color: #ffffff;
|
|
35
|
+
border: 1px solid #4f46e5;
|
|
36
|
+
}"
|
|
37
|
+
|
|
38
|
+
// Automatically replaces with:
|
|
39
|
+
.button {
|
|
40
|
+
background: var(--color-primary-500);
|
|
41
|
+
color: var(--color-white);
|
|
42
|
+
border: 1px solid var(--color-primary-600);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Complete Refactoring Examples
|
|
47
|
+
|
|
48
|
+
### Component Stylesheet
|
|
49
|
+
|
|
50
|
+
#### Before (Hardcoded Colors)
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
/* card.css - Original */
|
|
54
|
+
.card {
|
|
55
|
+
background: #ffffff;
|
|
56
|
+
border: 1px solid #e5e7eb;
|
|
57
|
+
border-radius: 8px;
|
|
58
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.card-header {
|
|
62
|
+
background: #f9fafb;
|
|
63
|
+
border-bottom: 1px solid #e5e7eb;
|
|
64
|
+
padding: 16px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.card-title {
|
|
68
|
+
color: #1f2937;
|
|
69
|
+
font-size: 18px;
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.card-body {
|
|
74
|
+
padding: 16px;
|
|
75
|
+
color: #4b5563;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.card-footer {
|
|
79
|
+
background: #f9fafb;
|
|
80
|
+
border-top: 1px solid #e5e7eb;
|
|
81
|
+
padding: 12px 16px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.card-link {
|
|
85
|
+
color: #6366f1;
|
|
86
|
+
text-decoration: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.card-link:hover {
|
|
90
|
+
color: #4f46e5;
|
|
91
|
+
text-decoration: underline;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Theme Variables
|
|
96
|
+
|
|
97
|
+
```css
|
|
98
|
+
/* theme.css */
|
|
99
|
+
:root {
|
|
100
|
+
/* Surfaces */
|
|
101
|
+
--color-surface: #ffffff;
|
|
102
|
+
--color-surface-variant: #f9fafb;
|
|
103
|
+
|
|
104
|
+
/* Borders */
|
|
105
|
+
--color-border: #e5e7eb;
|
|
106
|
+
|
|
107
|
+
/* Text */
|
|
108
|
+
--color-text-primary: #1f2937;
|
|
109
|
+
--color-text-secondary: #4b5563;
|
|
110
|
+
|
|
111
|
+
/* Brand */
|
|
112
|
+
--color-primary-500: #6366f1;
|
|
113
|
+
--color-primary-600: #4f46e5;
|
|
114
|
+
|
|
115
|
+
/* Shadows */
|
|
116
|
+
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
117
|
+
|
|
118
|
+
/* Spacing */
|
|
119
|
+
--spacing-3: 12px;
|
|
120
|
+
--spacing-4: 16px;
|
|
121
|
+
|
|
122
|
+
/* Typography */
|
|
123
|
+
--font-size-lg: 18px;
|
|
124
|
+
--font-weight-semibold: 600;
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### After (Refactored)
|
|
129
|
+
|
|
130
|
+
```css
|
|
131
|
+
/* card.css - Refactored */
|
|
132
|
+
.card {
|
|
133
|
+
background: var(--color-surface);
|
|
134
|
+
border: 1px solid var(--color-border);
|
|
135
|
+
border-radius: 8px;
|
|
136
|
+
box-shadow: var(--shadow-sm);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.card-header {
|
|
140
|
+
background: var(--color-surface-variant);
|
|
141
|
+
border-bottom: 1px solid var(--color-border);
|
|
142
|
+
padding: var(--spacing-4);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.card-title {
|
|
146
|
+
color: var(--color-text-primary);
|
|
147
|
+
font-size: var(--font-size-lg);
|
|
148
|
+
font-weight: var(--font-weight-semibold);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.card-body {
|
|
152
|
+
padding: var(--spacing-4);
|
|
153
|
+
color: var(--color-text-secondary);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.card-footer {
|
|
157
|
+
background: var(--color-surface-variant);
|
|
158
|
+
border-top: 1px solid var(--color-border);
|
|
159
|
+
padding: var(--spacing-3) var(--spacing-4);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.card-link {
|
|
163
|
+
color: var(--color-primary-500);
|
|
164
|
+
text-decoration: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.card-link:hover {
|
|
168
|
+
color: var(--color-primary-600);
|
|
169
|
+
text-decoration: underline;
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Form Styles Refactoring
|
|
174
|
+
|
|
175
|
+
#### Before
|
|
176
|
+
|
|
177
|
+
```css
|
|
178
|
+
/* forms.css - Original */
|
|
179
|
+
.form-group {
|
|
180
|
+
margin-bottom: 24px;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.form-label {
|
|
184
|
+
color: #374151;
|
|
185
|
+
font-size: 14px;
|
|
186
|
+
font-weight: 500;
|
|
187
|
+
margin-bottom: 8px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.form-input {
|
|
191
|
+
background: #ffffff;
|
|
192
|
+
border: 1px solid #d1d5db;
|
|
193
|
+
border-radius: 6px;
|
|
194
|
+
color: #1f2937;
|
|
195
|
+
padding: 8px 12px;
|
|
196
|
+
width: 100%;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.form-input:focus {
|
|
200
|
+
border-color: #6366f1;
|
|
201
|
+
outline: 2px solid rgba(99, 102, 241, 0.2);
|
|
202
|
+
outline-offset: 2px;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.form-input:disabled {
|
|
206
|
+
background: #f3f4f6;
|
|
207
|
+
color: #9ca3af;
|
|
208
|
+
cursor: not-allowed;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.form-error {
|
|
212
|
+
color: #ef4444;
|
|
213
|
+
font-size: 12px;
|
|
214
|
+
margin-top: 4px;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.form-hint {
|
|
218
|
+
color: #6b7280;
|
|
219
|
+
font-size: 12px;
|
|
220
|
+
margin-top: 4px;
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### After (With Original as Comments)
|
|
225
|
+
|
|
226
|
+
```css
|
|
227
|
+
/* forms.css - Refactored with preservation */
|
|
228
|
+
.form-group {
|
|
229
|
+
margin-bottom: 24px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.form-label {
|
|
233
|
+
color: var(--color-text-secondary); /* was: #374151 */
|
|
234
|
+
font-size: var(--font-size-sm); /* was: 14px */
|
|
235
|
+
font-weight: var(--font-weight-medium); /* was: 500 */
|
|
236
|
+
margin-bottom: var(--spacing-2); /* was: 8px */
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.form-input {
|
|
240
|
+
background: var(--color-surface); /* was: #ffffff */
|
|
241
|
+
border: 1px solid var(--color-border-light); /* was: #d1d5db */
|
|
242
|
+
border-radius: var(--radius-md); /* was: 6px */
|
|
243
|
+
color: var(--color-text-primary); /* was: #1f2937 */
|
|
244
|
+
padding: var(--spacing-2) var(--spacing-3); /* was: 8px 12px */
|
|
245
|
+
width: 100%;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.form-input:focus {
|
|
249
|
+
border-color: var(--color-primary-500); /* was: #6366f1 */
|
|
250
|
+
outline: 2px solid var(--color-primary-100); /* was: rgba(99, 102, 241, 0.2) */
|
|
251
|
+
outline-offset: 2px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.form-input:disabled {
|
|
255
|
+
background: var(--color-gray-100); /* was: #f3f4f6 */
|
|
256
|
+
color: var(--color-text-disabled); /* was: #9ca3af */
|
|
257
|
+
cursor: not-allowed;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.form-error {
|
|
261
|
+
color: var(--color-error); /* was: #ef4444 */
|
|
262
|
+
font-size: var(--font-size-xs); /* was: 12px */
|
|
263
|
+
margin-top: var(--spacing-1); /* was: 4px */
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.form-hint {
|
|
267
|
+
color: var(--color-text-muted); /* was: #6b7280 */
|
|
268
|
+
font-size: var(--font-size-xs); /* was: 12px */
|
|
269
|
+
margin-top: var(--spacing-1); /* was: 4px */
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Batch Color Processing
|
|
274
|
+
|
|
275
|
+
### Finding All Unique Colors
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
// Extract all colors from CSS
|
|
279
|
+
"Find all unique colors in this CSS file"
|
|
280
|
+
|
|
281
|
+
const css = `
|
|
282
|
+
.header { background: #1f2937; color: #ffffff; }
|
|
283
|
+
.nav { background: #374151; border-bottom: 1px solid #4b5563; }
|
|
284
|
+
.link { color: #6366f1; }
|
|
285
|
+
.link:hover { color: #4f46e5; }
|
|
286
|
+
.footer { background: #1f2937; color: #9ca3af; }
|
|
287
|
+
`;
|
|
288
|
+
|
|
289
|
+
// Result:
|
|
290
|
+
{
|
|
291
|
+
uniqueColors: [
|
|
292
|
+
"#1f2937", // Used 2 times
|
|
293
|
+
"#ffffff", // Used 1 time
|
|
294
|
+
"#374151", // Used 1 time
|
|
295
|
+
"#4b5563", // Used 1 time
|
|
296
|
+
"#6366f1", // Used 1 time
|
|
297
|
+
"#4f46e5", // Used 1 time
|
|
298
|
+
"#9ca3af" // Used 1 time
|
|
299
|
+
],
|
|
300
|
+
suggestions: [
|
|
301
|
+
"Color #1f2937 is used multiple times - consider creating a variable",
|
|
302
|
+
"7 unique colors found - consider consolidating similar shades"
|
|
303
|
+
]
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Batch Matching to Theme
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
// Match multiple colors at once
|
|
311
|
+
const colors = ["#6366f1", "#ec4899", "#10b981", "#f59e0b"];
|
|
312
|
+
const theme = `
|
|
313
|
+
:root {
|
|
314
|
+
--primary: #6366f1;
|
|
315
|
+
--accent: #ec4899;
|
|
316
|
+
--success: #10b981;
|
|
317
|
+
--warning: #f59e0b;
|
|
318
|
+
}
|
|
319
|
+
`;
|
|
320
|
+
|
|
321
|
+
// Results with confidence scores
|
|
322
|
+
[
|
|
323
|
+
{ color: "#6366f1", match: "--primary", confidence: 100 },
|
|
324
|
+
{ color: "#ec4899", match: "--accent", confidence: 100 },
|
|
325
|
+
{ color: "#10b981", match: "--success", confidence: 100 },
|
|
326
|
+
{ color: "#f59e0b", match: "--warning", confidence: 100 }
|
|
327
|
+
]
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Migration Strategies
|
|
331
|
+
|
|
332
|
+
### Progressive Enhancement
|
|
333
|
+
|
|
334
|
+
Start with high-confidence matches and gradually include lower confidence ones:
|
|
335
|
+
|
|
336
|
+
```javascript
|
|
337
|
+
// Step 1: Replace exact matches (100% confidence)
|
|
338
|
+
const exactMatches = refactorCSS(css, theme, { minConfidence: 100 });
|
|
339
|
+
|
|
340
|
+
// Step 2: Review and approve near matches (85-99% confidence)
|
|
341
|
+
const nearMatches = refactorCSS(css, theme, { minConfidence: 85 });
|
|
342
|
+
|
|
343
|
+
// Step 3: Handle remaining colors manually or create new variables
|
|
344
|
+
const remaining = findUnmatchedColors(css, theme);
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Department-by-Department Migration
|
|
348
|
+
|
|
349
|
+
Migrate large codebases incrementally:
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
// 1. Start with utility classes
|
|
353
|
+
refactorFile('styles/utilities.css', theme);
|
|
354
|
+
|
|
355
|
+
// 2. Then base components
|
|
356
|
+
refactorFile('styles/buttons.css', theme);
|
|
357
|
+
refactorFile('styles/forms.css', theme);
|
|
358
|
+
|
|
359
|
+
// 3. Finally, complex components
|
|
360
|
+
refactorFile('styles/navigation.css', theme);
|
|
361
|
+
refactorFile('styles/modals.css', theme);
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Creating Missing Variables
|
|
365
|
+
|
|
366
|
+
When colors don't match existing theme:
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
// Identify unmatched colors
|
|
370
|
+
const unmatched = [
|
|
371
|
+
{ color: "#7c3aed", usage: ["buttons", "links"] },
|
|
372
|
+
{ color: "#0ea5e9", usage: ["alerts", "badges"] }
|
|
373
|
+
];
|
|
374
|
+
|
|
375
|
+
// Generate appropriate variables
|
|
376
|
+
const newVariables = `
|
|
377
|
+
/* Additional theme colors */
|
|
378
|
+
--color-purple-500: #7c3aed;
|
|
379
|
+
--color-sky-500: #0ea5e9;
|
|
380
|
+
`;
|
|
381
|
+
|
|
382
|
+
// Update theme and re-refactor
|
|
383
|
+
const updatedTheme = theme + newVariables;
|
|
384
|
+
refactorCSS(css, updatedTheme);
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Context-Aware Refactoring
|
|
388
|
+
|
|
389
|
+
### Semantic Matching
|
|
390
|
+
|
|
391
|
+
The refactoring tool understands context:
|
|
392
|
+
|
|
393
|
+
```javascript
|
|
394
|
+
// Border colors prefer border variables
|
|
395
|
+
.card { border: 1px solid #e5e7eb; }
|
|
396
|
+
// → border: 1px solid var(--color-border);
|
|
397
|
+
|
|
398
|
+
// Text colors prefer text variables
|
|
399
|
+
.title { color: #1f2937; }
|
|
400
|
+
// → color: var(--color-text-primary);
|
|
401
|
+
|
|
402
|
+
// Backgrounds prefer surface variables
|
|
403
|
+
.modal { background: #ffffff; }
|
|
404
|
+
// → background: var(--color-surface);
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Confidence Levels
|
|
408
|
+
|
|
409
|
+
Understanding match confidence:
|
|
410
|
+
|
|
411
|
+
| Confidence | Meaning | Action |
|
|
412
|
+
|------------|---------|--------|
|
|
413
|
+
| 100% | Exact match | Auto-replace |
|
|
414
|
+
| 95-99% | Very close (ΔE < 2) | Auto-replace with comment |
|
|
415
|
+
| 85-94% | Close (ΔE < 5) | Suggest replacement |
|
|
416
|
+
| 70-84% | Similar (ΔE < 10) | Manual review |
|
|
417
|
+
| <70% | Different | Keep original |
|
|
418
|
+
|
|
419
|
+
### Handling Edge Cases
|
|
420
|
+
|
|
421
|
+
#### Gradients
|
|
422
|
+
|
|
423
|
+
```css
|
|
424
|
+
/* Before */
|
|
425
|
+
.gradient {
|
|
426
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* After */
|
|
430
|
+
.gradient {
|
|
431
|
+
background: linear-gradient(
|
|
432
|
+
135deg,
|
|
433
|
+
var(--color-purple-500) 0%,
|
|
434
|
+
var(--color-purple-700) 100%
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### RGBA Colors
|
|
440
|
+
|
|
441
|
+
```css
|
|
442
|
+
/* Before */
|
|
443
|
+
.overlay {
|
|
444
|
+
background: rgba(0, 0, 0, 0.5);
|
|
445
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/* After */
|
|
449
|
+
.overlay {
|
|
450
|
+
background: rgba(var(--color-black-rgb), 0.5);
|
|
451
|
+
border: 1px solid rgba(var(--color-white-rgb), 0.2);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/* Where theme includes: */
|
|
455
|
+
:root {
|
|
456
|
+
--color-black-rgb: 0, 0, 0;
|
|
457
|
+
--color-white-rgb: 255, 255, 255;
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
#### Box Shadows
|
|
462
|
+
|
|
463
|
+
```css
|
|
464
|
+
/* Before */
|
|
465
|
+
.card {
|
|
466
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* After */
|
|
470
|
+
.card {
|
|
471
|
+
box-shadow: var(--shadow-md);
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## Real-World Refactoring
|
|
476
|
+
|
|
477
|
+
### E-commerce Site
|
|
478
|
+
|
|
479
|
+
```css
|
|
480
|
+
/* Original product card */
|
|
481
|
+
.product-card {
|
|
482
|
+
background: white;
|
|
483
|
+
border: 1px solid #e0e0e0;
|
|
484
|
+
border-radius: 8px;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.product-image {
|
|
488
|
+
background: #f5f5f5;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.product-title {
|
|
492
|
+
color: #333333;
|
|
493
|
+
font-size: 18px;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.product-price {
|
|
497
|
+
color: #0066cc;
|
|
498
|
+
font-size: 24px;
|
|
499
|
+
font-weight: bold;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.product-sale-badge {
|
|
503
|
+
background: #ff4444;
|
|
504
|
+
color: white;
|
|
505
|
+
padding: 4px 8px;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.product-add-to-cart {
|
|
509
|
+
background: #00aa00;
|
|
510
|
+
color: white;
|
|
511
|
+
padding: 12px 24px;
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
```css
|
|
516
|
+
/* Refactored with design system */
|
|
517
|
+
.product-card {
|
|
518
|
+
background: var(--color-surface);
|
|
519
|
+
border: 1px solid var(--color-border);
|
|
520
|
+
border-radius: var(--radius-lg);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.product-image {
|
|
524
|
+
background: var(--color-surface-variant);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.product-title {
|
|
528
|
+
color: var(--color-text-primary);
|
|
529
|
+
font-size: var(--font-size-lg);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.product-price {
|
|
533
|
+
color: var(--color-primary);
|
|
534
|
+
font-size: var(--font-size-2xl);
|
|
535
|
+
font-weight: var(--font-weight-bold);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.product-sale-badge {
|
|
539
|
+
background: var(--color-error);
|
|
540
|
+
color: var(--color-on-error);
|
|
541
|
+
padding: var(--spacing-1) var(--spacing-2);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.product-add-to-cart {
|
|
545
|
+
background: var(--color-success);
|
|
546
|
+
color: var(--color-on-success);
|
|
547
|
+
padding: var(--spacing-3) var(--spacing-6);
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Dashboard Application
|
|
552
|
+
|
|
553
|
+
```css
|
|
554
|
+
/* Original dashboard styles */
|
|
555
|
+
.dashboard {
|
|
556
|
+
background: #f8f9fa;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.sidebar {
|
|
560
|
+
background: #2c3e50;
|
|
561
|
+
color: #ecf0f1;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.sidebar-item:hover {
|
|
565
|
+
background: #34495e;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.sidebar-item.active {
|
|
569
|
+
background: #3498db;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
.metric-card {
|
|
573
|
+
background: white;
|
|
574
|
+
border: 1px solid #dee2e6;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.metric-value {
|
|
578
|
+
color: #2c3e50;
|
|
579
|
+
font-size: 32px;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.metric-change.positive {
|
|
583
|
+
color: #27ae60;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.metric-change.negative {
|
|
587
|
+
color: #e74c3c;
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
```css
|
|
592
|
+
/* Refactored with consistent theme */
|
|
593
|
+
.dashboard {
|
|
594
|
+
background: var(--color-background);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.sidebar {
|
|
598
|
+
background: var(--color-surface-inverse);
|
|
599
|
+
color: var(--color-on-surface-inverse);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.sidebar-item:hover {
|
|
603
|
+
background: var(--color-surface-inverse-hover);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.sidebar-item.active {
|
|
607
|
+
background: var(--color-primary);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
.metric-card {
|
|
611
|
+
background: var(--color-surface);
|
|
612
|
+
border: 1px solid var(--color-outline);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.metric-value {
|
|
616
|
+
color: var(--color-on-surface);
|
|
617
|
+
font-size: var(--font-size-4xl);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.metric-change.positive {
|
|
621
|
+
color: var(--color-success);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.metric-change.negative {
|
|
625
|
+
color: var(--color-error);
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
## Automation Scripts
|
|
630
|
+
|
|
631
|
+
### Full Project Refactoring
|
|
632
|
+
|
|
633
|
+
```javascript
|
|
634
|
+
// refactor-project.js
|
|
635
|
+
const { refactorCSS, generateReport } = require('coolors-mcp');
|
|
636
|
+
const fs = require('fs');
|
|
637
|
+
const path = require('path');
|
|
638
|
+
|
|
639
|
+
async function refactorProject(srcDir, themeFile) {
|
|
640
|
+
const theme = fs.readFileSync(themeFile, 'utf-8');
|
|
641
|
+
const cssFiles = findCSSFiles(srcDir);
|
|
642
|
+
const results = [];
|
|
643
|
+
|
|
644
|
+
for (const file of cssFiles) {
|
|
645
|
+
const original = fs.readFileSync(file, 'utf-8');
|
|
646
|
+
const refactored = await refactorCSS(original, theme, {
|
|
647
|
+
minConfidence: 85,
|
|
648
|
+
preserveOriginal: true,
|
|
649
|
+
generateReport: true
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
// Backup original
|
|
653
|
+
fs.writeFileSync(`${file}.backup`, original);
|
|
654
|
+
|
|
655
|
+
// Write refactored
|
|
656
|
+
fs.writeFileSync(file, refactored.css);
|
|
657
|
+
|
|
658
|
+
results.push({
|
|
659
|
+
file,
|
|
660
|
+
changes: refactored.changes.length,
|
|
661
|
+
confidence: refactored.averageConfidence
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return generateReport(results);
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### Pre-commit Hook
|
|
670
|
+
|
|
671
|
+
```javascript
|
|
672
|
+
// .husky/pre-commit
|
|
673
|
+
#!/bin/sh
|
|
674
|
+
|
|
675
|
+
# Check for hardcoded colors in staged CSS files
|
|
676
|
+
staged_css=$(git diff --cached --name-only --diff-filter=ACM | grep '\.css$')
|
|
677
|
+
|
|
678
|
+
if [ -n "$staged_css" ]; then
|
|
679
|
+
for file in $staged_css; do
|
|
680
|
+
# Check for hex colors not using variables
|
|
681
|
+
if grep -E '#[0-9a-fA-F]{3,6}(?![0-9a-fA-F])' "$file" | grep -v 'var(--'; then
|
|
682
|
+
echo "⚠️ Warning: Hardcoded colors found in $file"
|
|
683
|
+
echo "Consider using theme variables instead"
|
|
684
|
+
exit 1
|
|
685
|
+
fi
|
|
686
|
+
done
|
|
687
|
+
fi
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
## Best Practices
|
|
691
|
+
|
|
692
|
+
### 1. Start with a Complete Theme
|
|
693
|
+
|
|
694
|
+
Before refactoring, ensure your theme covers all use cases:
|
|
695
|
+
|
|
696
|
+
```css
|
|
697
|
+
:root {
|
|
698
|
+
/* Surface colors */
|
|
699
|
+
--color-surface: #ffffff;
|
|
700
|
+
--color-surface-variant: #f5f5f5;
|
|
701
|
+
--color-surface-inverse: #1a1a1a;
|
|
702
|
+
|
|
703
|
+
/* Text colors */
|
|
704
|
+
--color-text-primary: #1a1a1a;
|
|
705
|
+
--color-text-secondary: #666666;
|
|
706
|
+
--color-text-disabled: #999999;
|
|
707
|
+
|
|
708
|
+
/* Interactive colors */
|
|
709
|
+
--color-primary: #6366f1;
|
|
710
|
+
--color-primary-hover: #4f46e5;
|
|
711
|
+
--color-primary-active: #4338ca;
|
|
712
|
+
|
|
713
|
+
/* Semantic colors */
|
|
714
|
+
--color-success: #10b981;
|
|
715
|
+
--color-warning: #f59e0b;
|
|
716
|
+
--color-error: #ef4444;
|
|
717
|
+
--color-info: #3b82f6;
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### 2. Use Semantic Naming
|
|
722
|
+
|
|
723
|
+
Choose variable names that describe purpose, not appearance:
|
|
724
|
+
|
|
725
|
+
```css
|
|
726
|
+
/* Good */
|
|
727
|
+
--color-text-primary
|
|
728
|
+
--color-surface-elevated
|
|
729
|
+
--color-interactive-hover
|
|
730
|
+
|
|
731
|
+
/* Avoid */
|
|
732
|
+
--color-black
|
|
733
|
+
--color-gray-light
|
|
734
|
+
--color-blue-dark
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
### 3. Preserve Original Values
|
|
738
|
+
|
|
739
|
+
Keep original values as comments for reference:
|
|
740
|
+
|
|
741
|
+
```css
|
|
742
|
+
.button {
|
|
743
|
+
background: var(--color-primary); /* was: #6366f1 */
|
|
744
|
+
}
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### 4. Test After Refactoring
|
|
748
|
+
|
|
749
|
+
Always verify visual appearance after refactoring:
|
|
750
|
+
|
|
751
|
+
```javascript
|
|
752
|
+
// Visual regression test
|
|
753
|
+
const screenshots = {
|
|
754
|
+
before: captureScreenshots(originalCSS),
|
|
755
|
+
after: captureScreenshots(refactoredCSS)
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
const differences = compareScreenshots(screenshots);
|
|
759
|
+
if (differences.length > 0) {
|
|
760
|
+
console.warn('Visual differences detected:', differences);
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### 5. Document Your Theme
|
|
765
|
+
|
|
766
|
+
Include documentation with your theme variables:
|
|
767
|
+
|
|
768
|
+
```css
|
|
769
|
+
:root {
|
|
770
|
+
/* Primary brand color - used for CTAs and primary actions */
|
|
771
|
+
--color-primary: #6366f1;
|
|
772
|
+
|
|
773
|
+
/* Text on primary color - must meet WCAG AA */
|
|
774
|
+
--color-on-primary: #ffffff;
|
|
775
|
+
|
|
776
|
+
/* Surface colors - ordered by elevation */
|
|
777
|
+
--color-surface-0: #ffffff; /* Base level */
|
|
778
|
+
--color-surface-1: #fafafa; /* Slightly elevated */
|
|
779
|
+
--color-surface-2: #f5f5f5; /* More elevated */
|
|
780
|
+
}
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
## Troubleshooting
|
|
784
|
+
|
|
785
|
+
### Common Issues and Solutions
|
|
786
|
+
|
|
787
|
+
#### Low Confidence Matches
|
|
788
|
+
|
|
789
|
+
**Problem**: Most matches have <70% confidence
|
|
790
|
+
**Solution**:
|
|
791
|
+
- Check if theme has enough color variations
|
|
792
|
+
- Consider adding intermediate shades
|
|
793
|
+
- Use more specific theme variables
|
|
794
|
+
|
|
795
|
+
#### Wrong Semantic Matches
|
|
796
|
+
|
|
797
|
+
**Problem**: Border colors matching to text variables
|
|
798
|
+
**Solution**:
|
|
799
|
+
- Use clearer variable naming conventions
|
|
800
|
+
- Provide context parameter when matching
|
|
801
|
+
- Create role-specific variables
|
|
802
|
+
|
|
803
|
+
#### Performance with Large Files
|
|
804
|
+
|
|
805
|
+
**Problem**: Slow refactoring for large CSS files
|
|
806
|
+
**Solution**:
|
|
807
|
+
- Split CSS into smaller modules
|
|
808
|
+
- Process files in parallel
|
|
809
|
+
- Cache theme parsing results
|
|
810
|
+
|
|
811
|
+
#### Gradient Refactoring
|
|
812
|
+
|
|
813
|
+
**Problem**: Complex gradients not refactoring correctly
|
|
814
|
+
**Solution**:
|
|
815
|
+
- Define gradient variables directly
|
|
816
|
+
- Use CSS custom properties for gradient stops
|
|
817
|
+
- Consider keeping complex gradients as-is
|
|
818
|
+
|
|
819
|
+
## Next Steps
|
|
820
|
+
|
|
821
|
+
- Learn about [Creating Themes](./creating-themes.md) to build comprehensive design systems
|
|
822
|
+
- Explore [Image Extraction](./image-extraction.md) for dynamic theme generation
|
|
823
|
+
- Read [Theme Matching Concepts](../concepts/theme-matching.md) to understand the algorithms
|
|
824
|
+
- Check [Material Design Tools](../tools/material-design.md) for advanced theming
|