colx 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.
Files changed (36) hide show
  1. package/README.md +111 -0
  2. package/dist/analyzer/color-parser.d.ts +18 -0
  3. package/dist/analyzer/color-parser.d.ts.map +1 -0
  4. package/dist/analyzer/color-parser.js +68 -0
  5. package/dist/analyzer/color-parser.js.map +1 -0
  6. package/dist/analyzer/consolidator.d.ts +13 -0
  7. package/dist/analyzer/consolidator.d.ts.map +1 -0
  8. package/dist/analyzer/consolidator.js +72 -0
  9. package/dist/analyzer/consolidator.js.map +1 -0
  10. package/dist/analyzer/similarity.d.ts +10 -0
  11. package/dist/analyzer/similarity.d.ts.map +1 -0
  12. package/dist/analyzer/similarity.js +72 -0
  13. package/dist/analyzer/similarity.js.map +1 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +104 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/scanner/color-extractor.d.ts +10 -0
  19. package/dist/scanner/color-extractor.d.ts.map +1 -0
  20. package/dist/scanner/color-extractor.js +98 -0
  21. package/dist/scanner/color-extractor.js.map +1 -0
  22. package/dist/scanner/file-walker.d.ts +2 -0
  23. package/dist/scanner/file-walker.d.ts.map +1 -0
  24. package/dist/scanner/file-walker.js +45 -0
  25. package/dist/scanner/file-walker.js.map +1 -0
  26. package/dist/server/api.d.ts +33 -0
  27. package/dist/server/api.d.ts.map +1 -0
  28. package/dist/server/api.js +72 -0
  29. package/dist/server/api.js.map +1 -0
  30. package/dist/server/server.d.ts +4 -0
  31. package/dist/server/server.d.ts.map +1 -0
  32. package/dist/server/server.js +41 -0
  33. package/dist/server/server.js.map +1 -0
  34. package/package.json +51 -0
  35. package/src/ui/app.jsx +277 -0
  36. package/src/ui/index.html +341 -0
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # Tailwind Color Visualizer
2
+
3
+ A CLI tool that scans TypeScript/JSX files for Tailwind arbitrary color values, visualizes them in a coolors.co-style web UI, and provides suggestions for CSS variable consolidation and color merging opportunities.
4
+
5
+ ## Features
6
+
7
+ - 🔍 **Scan** `.tsx` and `.jsx` files for Tailwind arbitrary color values
8
+ - 🎨 **Visualize** colors in a beautiful web interface (similar to coolors.co)
9
+ - 💡 **Suggest** CSS variable consolidation for duplicate colors
10
+ - 🔬 **Detect** similar colors and suggest merges using Delta E color difference
11
+ - 📊 **Statistics** about color usage across your codebase
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install -g colx
17
+ ```
18
+
19
+ Or use with npx (no installation required):
20
+
21
+ ```bash
22
+ npx colx [directory]
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Basic Usage
28
+
29
+ Scan the current directory:
30
+
31
+ ```bash
32
+ colx
33
+ ```
34
+
35
+ Or specify a directory:
36
+
37
+ ```bash
38
+ colx ./src
39
+ ```
40
+
41
+ ### Options
42
+
43
+ - `--port <number>` - Server port (default: 6969)
44
+ - `--no-open` - Don't open browser automatically
45
+ - `--threshold <number>` - Color similarity threshold for merge suggestions (default: 5)
46
+
47
+ ### Examples
48
+
49
+ ```bash
50
+ # Scan a specific directory
51
+ colx ./my-project/src
52
+
53
+ # Use a custom port
54
+ colx --port 8080
55
+
56
+ # Don't open browser automatically
57
+ colx --no-open
58
+
59
+ # Adjust similarity threshold (lower = more strict)
60
+ colx --threshold 3
61
+ ```
62
+
63
+ ## Supported Color Formats
64
+
65
+ The tool detects Tailwind arbitrary values in the following formats:
66
+
67
+ - **Hex**: `bg-[#ff5733]`, `text-[#ABC]`
68
+ - **RGB**: `bg-[rgb(255,87,51)]`
69
+ - **RGBA**: `bg-[rgba(255,87,51,0.5)]`
70
+ - **HSL**: `bg-[hsl(9,100%,50%)]`
71
+ - **HSLA**: `bg-[hsla(9,100%,50%,0.5)]`
72
+
73
+ ## What It Does
74
+
75
+ 1. **Scans** your codebase for `.tsx` and `.jsx` files
76
+ 2. **Extracts** all Tailwind arbitrary color values
77
+ 3. **Normalizes** colors to hex format for comparison
78
+ 4. **Analyzes** color similarities using Delta E (CIEDE2000)
79
+ 5. **Suggests** CSS variable consolidation for duplicate colors
80
+ 6. **Suggests** color merges for visually similar colors
81
+ 7. **Displays** everything in a beautiful web interface
82
+
83
+ ## Output
84
+
85
+ The tool launches a web server and opens your browser to display:
86
+
87
+ - **Color Palette**: Grid view of all unique colors found
88
+ - **Color Details**: Click any color to see where it's used
89
+ - **Filter by Utility Class**: Filter colors by bg, text, border, etc.
90
+ - **Merge Suggestions**: Groups of similar colors that could be merged
91
+
92
+ ## Development
93
+
94
+ ```bash
95
+ # Install dependencies
96
+ npm install
97
+
98
+ # Build TypeScript
99
+ npm run build
100
+
101
+ # Run in development mode (with Bun)
102
+ bun run src/index.ts
103
+
104
+ # Or with Node.js
105
+ npm run dev
106
+ ```
107
+
108
+ ## Requirements
109
+
110
+ - Node.js >= 16 (or Bun)
111
+ - TypeScript projects with `.tsx` or `.jsx` files
@@ -0,0 +1,18 @@
1
+ export interface ParsedColor {
2
+ hex: string;
3
+ originalValue: string;
4
+ format: 'hex' | 'rgb' | 'rgba' | 'hsl' | 'hsla';
5
+ }
6
+ /**
7
+ * Normalize a color value to hex format
8
+ * Handles hex, rgb, rgba, hsl, and hsla formats
9
+ */
10
+ export declare function parseColor(value: string, format: ParsedColor['format']): ParsedColor | null;
11
+ /**
12
+ * Parse multiple color values and return unique parsed colors
13
+ */
14
+ export declare function parseColors(occurrences: Array<{
15
+ originalValue: string;
16
+ format: ParsedColor['format'];
17
+ }>): Map<string, ParsedColor>;
18
+ //# sourceMappingURL=color-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-parser.d.ts","sourceRoot":"","sources":["../../src/analyzer/color-parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,WAAW,GAAG,IAAI,CA6C3F;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,KAAK,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAC,GAC3E,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAc1B"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseColor = parseColor;
7
+ exports.parseColors = parseColors;
8
+ const chroma_js_1 = __importDefault(require("chroma-js"));
9
+ /**
10
+ * Normalize a color value to hex format
11
+ * Handles hex, rgb, rgba, hsl, and hsla formats
12
+ */
13
+ function parseColor(value, format) {
14
+ try {
15
+ let chromaColor;
16
+ switch (format) {
17
+ case 'hex':
18
+ // Handle 3-digit hex (#ABC -> #AABBCC)
19
+ if (value.length === 4) {
20
+ value = `#${value[1]}${value[1]}${value[2]}${value[2]}${value[3]}${value[3]}`;
21
+ }
22
+ chromaColor = (0, chroma_js_1.default)(value);
23
+ break;
24
+ case 'rgb':
25
+ chromaColor = (0, chroma_js_1.default)(`rgb(${value})`);
26
+ break;
27
+ case 'rgba':
28
+ chromaColor = (0, chroma_js_1.default)(`rgba(${value})`);
29
+ break;
30
+ case 'hsl':
31
+ chromaColor = (0, chroma_js_1.default)(`hsl(${value})`);
32
+ break;
33
+ case 'hsla':
34
+ chromaColor = (0, chroma_js_1.default)(`hsla(${value})`);
35
+ break;
36
+ default:
37
+ return null;
38
+ }
39
+ // Normalize to hex (uppercase, no alpha)
40
+ const hex = chromaColor.hex().toUpperCase();
41
+ return {
42
+ hex,
43
+ originalValue: value,
44
+ format
45
+ };
46
+ }
47
+ catch (error) {
48
+ // Invalid color format
49
+ return null;
50
+ }
51
+ }
52
+ /**
53
+ * Parse multiple color values and return unique parsed colors
54
+ */
55
+ function parseColors(occurrences) {
56
+ const colorMap = new Map();
57
+ for (const occurrence of occurrences) {
58
+ const parsed = parseColor(occurrence.originalValue, occurrence.format);
59
+ if (parsed) {
60
+ // Use hex as the key to deduplicate
61
+ if (!colorMap.has(parsed.hex)) {
62
+ colorMap.set(parsed.hex, parsed);
63
+ }
64
+ }
65
+ }
66
+ return colorMap;
67
+ }
68
+ //# sourceMappingURL=color-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-parser.js","sourceRoot":"","sources":["../../src/analyzer/color-parser.ts"],"names":[],"mappings":";;;;;AAYA,gCA6CC;AAKD,kCAgBC;AA9ED,0DAA+B;AAQ/B;;;GAGG;AACH,SAAgB,UAAU,CAAC,KAAa,EAAE,MAA6B;IACrE,IAAI,CAAC;QACH,IAAI,WAAyB,CAAC;QAE9B,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,KAAK;gBACR,uCAAuC;gBACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACvB,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChF,CAAC;gBACD,WAAW,GAAG,IAAA,mBAAM,EAAC,KAAK,CAAC,CAAC;gBAC5B,MAAM;YAER,KAAK,KAAK;gBACR,WAAW,GAAG,IAAA,mBAAM,EAAC,OAAO,KAAK,GAAG,CAAC,CAAC;gBACtC,MAAM;YAER,KAAK,MAAM;gBACT,WAAW,GAAG,IAAA,mBAAM,EAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;gBACvC,MAAM;YAER,KAAK,KAAK;gBACR,WAAW,GAAG,IAAA,mBAAM,EAAC,OAAO,KAAK,GAAG,CAAC,CAAC;gBACtC,MAAM;YAER,KAAK,MAAM;gBACT,WAAW,GAAG,IAAA,mBAAM,EAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;gBACvC,MAAM;YAER;gBACE,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,yCAAyC;QACzC,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;QAE5C,OAAO;YACL,GAAG;YACH,aAAa,EAAE,KAAK;YACpB,MAAM;SACP,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uBAAuB;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CACzB,WAA4E;IAE5E,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAEhD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,aAAa,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QACvE,IAAI,MAAM,EAAE,CAAC;YACX,oCAAoC;YACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9B,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { ColorOccurrence } from '../scanner/color-extractor';
2
+ export interface CSSVariableSuggestion {
3
+ variable: string;
4
+ value: string;
5
+ occurrences: number;
6
+ files: string[];
7
+ hex: string;
8
+ }
9
+ /**
10
+ * Consolidate duplicate colors into CSS variable suggestions
11
+ */
12
+ export declare function consolidateToCSSVariables(occurrences: ColorOccurrence[]): CSSVariableSuggestion[];
13
+ //# sourceMappingURL=consolidator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidator.d.ts","sourceRoot":"","sources":["../../src/analyzer/consolidator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAG7D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AA4BD;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,eAAe,EAAE,GAC7B,qBAAqB,EAAE,CAmDzB"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.consolidateToCSSVariables = consolidateToCSSVariables;
4
+ const color_parser_1 = require("./color-parser");
5
+ /**
6
+ * Generate CSS variable name from color value or usage
7
+ */
8
+ function generateVariableName(hex, index) {
9
+ // Try to generate semantic names based on color properties
10
+ // For now, use generic names like --color-primary, --color-accent, etc.
11
+ const names = [
12
+ 'primary',
13
+ 'secondary',
14
+ 'accent',
15
+ 'background',
16
+ 'foreground',
17
+ 'muted',
18
+ 'border',
19
+ 'ring',
20
+ 'shadow'
21
+ ];
22
+ if (index < names.length) {
23
+ return `--color-${names[index]}`;
24
+ }
25
+ // Fallback to indexed names
26
+ return `--color-${index + 1}`;
27
+ }
28
+ /**
29
+ * Consolidate duplicate colors into CSS variable suggestions
30
+ */
31
+ function consolidateToCSSVariables(occurrences) {
32
+ // Group occurrences by hex value
33
+ const hexGroups = new Map();
34
+ for (const occurrence of occurrences) {
35
+ // Parse the color to get its hex value
36
+ const parsedMap = (0, color_parser_1.parseColors)([{
37
+ originalValue: occurrence.originalValue,
38
+ format: occurrence.format
39
+ }]);
40
+ // Get the parsed color (should only be one)
41
+ const parsed = Array.from(parsedMap.values())[0];
42
+ if (parsed) {
43
+ const hex = parsed.hex;
44
+ if (!hexGroups.has(hex)) {
45
+ hexGroups.set(hex, {
46
+ occurrences: [],
47
+ parsed
48
+ });
49
+ }
50
+ hexGroups.get(hex).occurrences.push(occurrence);
51
+ }
52
+ }
53
+ // Generate suggestions for colors that appear multiple times
54
+ const suggestions = [];
55
+ let variableIndex = 0;
56
+ for (const [hex, group] of hexGroups.entries()) {
57
+ if (group.occurrences.length > 1) {
58
+ const uniqueFiles = [...new Set(group.occurrences.map(o => o.file))];
59
+ suggestions.push({
60
+ variable: generateVariableName(hex, variableIndex),
61
+ value: group.parsed.originalValue,
62
+ occurrences: group.occurrences.length,
63
+ files: uniqueFiles,
64
+ hex
65
+ });
66
+ variableIndex++;
67
+ }
68
+ }
69
+ // Sort by occurrences (most used first)
70
+ return suggestions.sort((a, b) => b.occurrences - a.occurrences);
71
+ }
72
+ //# sourceMappingURL=consolidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidator.js","sourceRoot":"","sources":["../../src/analyzer/consolidator.ts"],"names":[],"mappings":";;AAwCA,8DAqDC;AA5FD,iDAA0D;AAU1D;;GAEG;AACH,SAAS,oBAAoB,CAAC,GAAW,EAAE,KAAa;IACtD,2DAA2D;IAC3D,wEAAwE;IACxE,MAAM,KAAK,GAAG;QACZ,SAAS;QACT,WAAW;QACX,QAAQ;QACR,YAAY;QACZ,YAAY;QACZ,OAAO;QACP,QAAQ;QACR,MAAM;QACN,QAAQ;KACT,CAAC;IAEF,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACzB,OAAO,WAAW,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;IACnC,CAAC;IAED,4BAA4B;IAC5B,OAAO,WAAW,KAAK,GAAG,CAAC,EAAE,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAgB,yBAAyB,CACvC,WAA8B;IAE9B,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAI,GAAG,EAGrB,CAAC;IAEL,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,uCAAuC;QACvC,MAAM,SAAS,GAAG,IAAA,0BAAW,EAAC,CAAC;gBAC7B,aAAa,EAAE,UAAU,CAAC,aAAa;gBACvC,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC,CAAC;QAEJ,4CAA4C;QAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;YACvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE;oBACjB,WAAW,EAAE,EAAE;oBACf,MAAM;iBACP,CAAC,CAAC;YACL,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,MAAM,WAAW,GAA4B,EAAE,CAAC;IAChD,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAErE,WAAW,CAAC,IAAI,CAAC;gBACf,QAAQ,EAAE,oBAAoB,CAAC,GAAG,EAAE,aAAa,CAAC;gBAClD,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,aAAa;gBACjC,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM;gBACrC,KAAK,EAAE,WAAW;gBAClB,GAAG;aACJ,CAAC,CAAC;YAEH,aAAa,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface SimilarColorGroup {
2
+ colors: string[];
3
+ suggestedColor: string;
4
+ averageSimilarity: number;
5
+ }
6
+ /**
7
+ * Find similar color groups using Delta E threshold
8
+ */
9
+ export declare function findSimilarColors(colors: string[], threshold?: number): SimilarColorGroup[];
10
+ //# sourceMappingURL=similarity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../../src/analyzer/similarity.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AA2BD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,SAAS,GAAE,MAAU,GACpB,iBAAiB,EAAE,CA4CrB"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.findSimilarColors = findSimilarColors;
7
+ const chroma_js_1 = __importDefault(require("chroma-js"));
8
+ /**
9
+ * Calculate Delta E (CIEDE2000) color difference
10
+ * Lower values mean colors are more similar
11
+ */
12
+ function calculateDeltaE(color1, color2) {
13
+ try {
14
+ const c1 = (0, chroma_js_1.default)(color1);
15
+ const c2 = (0, chroma_js_1.default)(color2);
16
+ // Get LAB values for Delta E calculation
17
+ const lab1 = c1.lab();
18
+ const lab2 = c2.lab();
19
+ // Simple Delta E calculation (Euclidean distance in LAB space)
20
+ // For more accurate CIEDE2000, we'd need a specialized library
21
+ const deltaL = lab1[0] - lab2[0];
22
+ const deltaA = lab1[1] - lab2[1];
23
+ const deltaB = lab1[2] - lab2[2];
24
+ return Math.sqrt(deltaL * deltaL + deltaA * deltaA + deltaB * deltaB);
25
+ }
26
+ catch (error) {
27
+ return Infinity; // Colors are very different if we can't compare
28
+ }
29
+ }
30
+ /**
31
+ * Find similar color groups using Delta E threshold
32
+ */
33
+ function findSimilarColors(colors, threshold = 5) {
34
+ if (colors.length === 0)
35
+ return [];
36
+ const groups = [];
37
+ const processed = new Set();
38
+ for (let i = 0; i < colors.length; i++) {
39
+ const color1 = colors[i];
40
+ if (processed.has(color1))
41
+ continue;
42
+ const similarColors = [color1];
43
+ const similarities = [];
44
+ // Find all colors similar to color1
45
+ for (let j = i + 1; j < colors.length; j++) {
46
+ const color2 = colors[j];
47
+ if (processed.has(color2))
48
+ continue;
49
+ const deltaE = calculateDeltaE(color1, color2);
50
+ if (deltaE <= threshold) {
51
+ similarColors.push(color2);
52
+ similarities.push(deltaE);
53
+ processed.add(color2);
54
+ }
55
+ }
56
+ if (similarColors.length > 1) {
57
+ // Calculate average similarity
58
+ const avgSimilarity = similarities.length > 0
59
+ ? similarities.reduce((a, b) => a + b, 0) / similarities.length
60
+ : 0;
61
+ // Suggest the first color as the merge target (could be improved with better logic)
62
+ groups.push({
63
+ colors: similarColors,
64
+ suggestedColor: color1,
65
+ averageSimilarity: avgSimilarity
66
+ });
67
+ }
68
+ processed.add(color1);
69
+ }
70
+ return groups;
71
+ }
72
+ //# sourceMappingURL=similarity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity.js","sourceRoot":"","sources":["../../src/analyzer/similarity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const path_1 = require("path");
6
+ const fs_1 = require("fs");
7
+ const file_walker_1 = require("./scanner/file-walker");
8
+ const color_extractor_1 = require("./scanner/color-extractor");
9
+ const color_parser_1 = require("./analyzer/color-parser");
10
+ const similarity_1 = require("./analyzer/similarity");
11
+ const consolidator_1 = require("./analyzer/consolidator");
12
+ const server_1 = require("./server/server");
13
+ const api_1 = require("./server/api");
14
+ function findUiDirectory() {
15
+ // Try multiple possible paths
16
+ const possiblePaths = [
17
+ // Development (running from src/)
18
+ (0, path_1.resolve)(__dirname, 'ui'),
19
+ // Production (running from dist/)
20
+ (0, path_1.resolve)(__dirname, '../src/ui'),
21
+ // Installed package
22
+ (0, path_1.resolve)(__dirname, '../../src/ui'),
23
+ ];
24
+ for (const path of possiblePaths) {
25
+ if ((0, fs_1.existsSync)(path) && (0, fs_1.existsSync)((0, path_1.join)(path, 'index.html'))) {
26
+ return path;
27
+ }
28
+ }
29
+ // Fallback to first path
30
+ return possiblePaths[0];
31
+ }
32
+ const program = new commander_1.Command();
33
+ program
34
+ .name('tailwind-color-visualizer')
35
+ .description('Scan and visualize Tailwind arbitrary color values')
36
+ .version('1.0.0')
37
+ .argument('[directory]', 'Directory to scan (default: current directory)', process.cwd())
38
+ .option('-p, --port <number>', 'Server port', '6969')
39
+ .option('--no-open', 'Do not open browser automatically')
40
+ .option('-t, --threshold <number>', 'Color similarity threshold (Delta E)', '5')
41
+ .action(async (directory, options) => {
42
+ const targetDir = (0, path_1.resolve)(directory);
43
+ const port = parseInt(options.port, 10);
44
+ const threshold = parseFloat(options.threshold);
45
+ const shouldOpen = options.open !== false;
46
+ console.log('🔍 Scanning for Tailwind arbitrary color values...\n');
47
+ console.log(`📁 Directory: ${targetDir}`);
48
+ console.log(`🎨 Similarity threshold: ${threshold}`);
49
+ console.log('');
50
+ try {
51
+ // Phase 1: Find and scan files
52
+ console.log('📂 Finding .tsx and .jsx files...');
53
+ const files = await (0, file_walker_1.findTsxJsxFiles)(targetDir);
54
+ console.log(` Found ${files.length} file${files.length !== 1 ? 's' : ''}`);
55
+ if (files.length === 0) {
56
+ console.log('\n⚠️ No .tsx or .jsx files found in the specified directory.');
57
+ process.exit(1);
58
+ }
59
+ // Phase 2: Extract colors
60
+ console.log('\n🎨 Extracting color values...');
61
+ const occurrences = await (0, color_extractor_1.extractColorsFromFiles)(files);
62
+ console.log(` Found ${occurrences.length} color occurrence${occurrences.length !== 1 ? 's' : ''}`);
63
+ if (occurrences.length === 0) {
64
+ console.log('\n⚠️ No Tailwind arbitrary color values found.');
65
+ process.exit(1);
66
+ }
67
+ // Phase 3: Parse and normalize colors
68
+ console.log('\n🔬 Parsing and normalizing colors...');
69
+ const parsedColors = (0, color_parser_1.parseColors)(occurrences.map(occ => ({
70
+ originalValue: occ.originalValue,
71
+ format: occ.format
72
+ })));
73
+ console.log(` Found ${parsedColors.size} unique color${parsedColors.size !== 1 ? 's' : ''}`);
74
+ // Phase 4: Analyze similarities
75
+ console.log('\n🔍 Analyzing color similarities...');
76
+ const uniqueHexColors = Array.from(parsedColors.keys());
77
+ const similarGroups = (0, similarity_1.findSimilarColors)(uniqueHexColors, threshold);
78
+ console.log(` Found ${similarGroups.length} group${similarGroups.length !== 1 ? 's' : ''} of similar colors`);
79
+ // Phase 5: Generate CSS variable suggestions
80
+ console.log('\n💡 Generating CSS variable suggestions...');
81
+ const cssVariables = (0, consolidator_1.consolidateToCSSVariables)(occurrences);
82
+ console.log(` Generated ${cssVariables.length} CSS variable suggestion${cssVariables.length !== 1 ? 's' : ''}`);
83
+ // Phase 6: Setup API data
84
+ (0, api_1.setColorData)(occurrences, parsedColors, similarGroups, cssVariables);
85
+ // Phase 7: Start server
86
+ console.log('\n🚀 Starting web server...');
87
+ const uiDir = findUiDirectory();
88
+ await (0, server_1.startServer)(port, uiDir, shouldOpen);
89
+ // Keep the process alive
90
+ process.on('SIGINT', () => {
91
+ console.log('\n\n👋 Shutting down...');
92
+ process.exit(0);
93
+ });
94
+ }
95
+ catch (error) {
96
+ console.error('\n❌ Error:', error instanceof Error ? error.message : String(error));
97
+ if (error instanceof Error && error.stack) {
98
+ console.error(error.stack);
99
+ }
100
+ process.exit(1);
101
+ }
102
+ });
103
+ program.parse();
104
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface ColorOccurrence {
2
+ file: string;
3
+ line: number;
4
+ className: string;
5
+ originalValue: string;
6
+ format: 'hex' | 'rgb' | 'rgba' | 'hsl' | 'hsla';
7
+ }
8
+ export declare function extractColorsFromFile(filePath: string): Promise<ColorOccurrence[]>;
9
+ export declare function extractColorsFromFiles(filePaths: string[]): Promise<ColorOccurrence[]>;
10
+ //# sourceMappingURL=color-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-extractor.d.ts","sourceRoot":"","sources":["../../src/scanner/color-extractor.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CACjD;AAyCD,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAwExF;AAED,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAS5F"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractColorsFromFile = extractColorsFromFile;
4
+ exports.extractColorsFromFiles = extractColorsFromFiles;
5
+ const promises_1 = require("fs/promises");
6
+ // Tailwind utility prefixes that support color arbitrary values
7
+ const COLOR_PREFIXES = [
8
+ 'bg', 'text', 'border', 'ring', 'outline', 'divide', 'from', 'via', 'to',
9
+ 'decoration', 'accent', 'caret', 'fill', 'stroke', 'shadow'
10
+ ];
11
+ // Build regex pattern for all color prefixes
12
+ const prefixPattern = COLOR_PREFIXES.join('|');
13
+ // Hex color pattern: bg-[#ff5733], text-[#ABC]
14
+ const hexPattern = new RegExp(`(?:${prefixPattern})-\\[#([0-9a-fA-F]{3,8})\\]`, 'g');
15
+ // RGB pattern: bg-[rgb(255,87,51)]
16
+ const rgbPattern = new RegExp(`(?:${prefixPattern})-\\[rgb\\(([^)]+)\\)\\]`, 'g');
17
+ // RGBA pattern: bg-[rgba(255,87,51,0.5)]
18
+ const rgbaPattern = new RegExp(`(?:${prefixPattern})-\\[rgba\\(([^)]+)\\)\\]`, 'g');
19
+ // HSL pattern: bg-[hsl(9,100%,50%)]
20
+ const hslPattern = new RegExp(`(?:${prefixPattern})-\\[hsl\\(([^)]+)\\)\\]`, 'g');
21
+ // HSLA pattern: bg-[hsla(9,100%,50%,0.5)]
22
+ const hslaPattern = new RegExp(`(?:${prefixPattern})-\\[hsla\\(([^)]+)\\)\\]`, 'g');
23
+ async function extractColorsFromFile(filePath) {
24
+ const occurrences = [];
25
+ try {
26
+ const content = await (0, promises_1.readFile)(filePath, 'utf-8');
27
+ const lines = content.split('\n');
28
+ // Extract hex colors
29
+ let match;
30
+ while ((match = hexPattern.exec(content)) !== null) {
31
+ const lineNumber = content.substring(0, match.index).split('\n').length;
32
+ occurrences.push({
33
+ file: filePath,
34
+ line: lineNumber,
35
+ className: match[0],
36
+ originalValue: `#${match[1]}`,
37
+ format: 'hex'
38
+ });
39
+ }
40
+ // Extract RGB colors
41
+ while ((match = rgbPattern.exec(content)) !== null) {
42
+ const lineNumber = content.substring(0, match.index).split('\n').length;
43
+ occurrences.push({
44
+ file: filePath,
45
+ line: lineNumber,
46
+ className: match[0],
47
+ originalValue: `rgb(${match[1]})`,
48
+ format: 'rgb'
49
+ });
50
+ }
51
+ // Extract RGBA colors
52
+ while ((match = rgbaPattern.exec(content)) !== null) {
53
+ const lineNumber = content.substring(0, match.index).split('\n').length;
54
+ occurrences.push({
55
+ file: filePath,
56
+ line: lineNumber,
57
+ className: match[0],
58
+ originalValue: `rgba(${match[1]})`,
59
+ format: 'rgba'
60
+ });
61
+ }
62
+ // Extract HSL colors
63
+ while ((match = hslPattern.exec(content)) !== null) {
64
+ const lineNumber = content.substring(0, match.index).split('\n').length;
65
+ occurrences.push({
66
+ file: filePath,
67
+ line: lineNumber,
68
+ className: match[0],
69
+ originalValue: `hsl(${match[1]})`,
70
+ format: 'hsl'
71
+ });
72
+ }
73
+ // Extract HSLA colors
74
+ while ((match = hslaPattern.exec(content)) !== null) {
75
+ const lineNumber = content.substring(0, match.index).split('\n').length;
76
+ occurrences.push({
77
+ file: filePath,
78
+ line: lineNumber,
79
+ className: match[0],
80
+ originalValue: `hsla(${match[1]})`,
81
+ format: 'hsla'
82
+ });
83
+ }
84
+ }
85
+ catch (error) {
86
+ console.warn(`Warning: Could not read file ${filePath}: ${error}`);
87
+ }
88
+ return occurrences;
89
+ }
90
+ async function extractColorsFromFiles(filePaths) {
91
+ const allOccurrences = [];
92
+ for (const filePath of filePaths) {
93
+ const occurrences = await extractColorsFromFile(filePath);
94
+ allOccurrences.push(...occurrences);
95
+ }
96
+ return allOccurrences;
97
+ }
98
+ //# sourceMappingURL=color-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-extractor.js","sourceRoot":"","sources":["../../src/scanner/color-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function findTsxJsxFiles(rootDir: string): Promise<string[]>;
2
+ //# sourceMappingURL=file-walker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-walker.d.ts","sourceRoot":"","sources":["../../src/scanner/file-walker.ts"],"names":[],"mappings":"AAKA,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwCxE"}