|
1 | 1 | #!/usr/bin/env node |
2 | 2 |
|
3 | 3 | const pairs = [ |
4 | | - { fg: "#000000", bg: "#ffffff", name: "text on bg (solar)" }, |
5 | | - { fg: "#1a1a1a", bg: "#ffffff", name: "text-secondary on bg (solar)" }, |
6 | | - { fg: "#2a2a2a", bg: "#ffffff", name: "text-tertiary on bg (solar)" }, |
7 | | - { fg: "#0022cc", bg: "#ffffff", name: "primary on bg (solar)" }, |
8 | | - { fg: "#001999", bg: "#ffffff", name: "primary-hover on bg (solar)" }, |
9 | | - { fg: "#ffffff", bg: "#0022cc", name: "primary-text on primary (solar)" }, |
10 | | - { fg: "#004d00", bg: "#ffffff", name: "secondary on bg (solar)" }, |
11 | | - { fg: "#8b0000", bg: "#ffffff", name: "danger on bg (solar)" }, |
12 | | - { fg: "#8b0000", bg: "#ffffff", name: "danger-text on bg (solar)" }, |
13 | | - { fg: "#4a3a00", bg: "#ffffff", name: "warning on bg (solar)" }, |
14 | | - { fg: "#3a2e00", bg: "#ffffff", name: "warning-fill on bg (solar)" }, |
15 | | - { fg: "#000000", bg: "#f5f5f5", name: "text on surface (solar)" }, |
16 | | - { fg: "#001999", bg: "#e0e8ff", name: "tag-text on tag-bg (solar)" }, |
17 | | - { fg: "#ffffff", bg: "#000000", name: "nav-text on nav-bg (solar)" }, |
18 | | - { fg: "#000000", bg: "#ffffff", name: "focus-ring on bg (solar)" }, |
19 | | - { fg: "#171717", bg: "#ffffff", name: "text on bg (light)" }, |
20 | | - { fg: "#6f5f48", bg: "#f7f4ee", name: "text-secondary on bg (light)" }, |
21 | | - { fg: "#0f766e", bg: "#f7f4ee", name: "primary on bg (light)" }, |
22 | | - { fg: "#ffffff", bg: "#0f766e", name: "primary-text on primary (light)" }, |
23 | | - { fg: "#ededed", bg: "#0a0a0a", name: "text on bg (dark)" }, |
24 | | - { fg: "#2dd4bf", bg: "#0a0a0a", name: "primary on bg (dark)" }, |
25 | | - { fg: "#0a0a0a", bg: "#2dd4bf", name: "primary-text on primary (dark)" }, |
| 4 | + { fg: "#000000", bg: "#ffffff", name: "text on bg (solar)", required: 10 }, |
| 5 | + { fg: "#1a1a1a", bg: "#ffffff", name: "text-secondary on bg (solar)", required: 10 }, |
| 6 | + { fg: "#2a2a2a", bg: "#ffffff", name: "text-tertiary on bg (solar)", required: 10 }, |
| 7 | + { fg: "#0022cc", bg: "#ffffff", name: "primary on bg (solar)", required: 10 }, |
| 8 | + { fg: "#001999", bg: "#ffffff", name: "primary-hover on bg (solar)", required: 10 }, |
| 9 | + { fg: "#ffffff", bg: "#0022cc", name: "primary-text on primary (solar)", required: 10 }, |
| 10 | + { fg: "#004d00", bg: "#ffffff", name: "secondary on bg (solar)", required: 10 }, |
| 11 | + { fg: "#8b0000", bg: "#ffffff", name: "danger on bg (solar)", required: 10 }, |
| 12 | + { fg: "#8b0000", bg: "#ffffff", name: "danger-text on bg (solar)", required: 10 }, |
| 13 | + { fg: "#4a3a00", bg: "#ffffff", name: "warning on bg (solar)", required: 10 }, |
| 14 | + { fg: "#3a2e00", bg: "#ffffff", name: "warning-fill on bg (solar)", required: 10 }, |
| 15 | + { fg: "#000000", bg: "#f5f5f5", name: "text on surface (solar)", required: 10 }, |
| 16 | + { fg: "#001999", bg: "#e0e8ff", name: "tag-text on tag-bg (solar)", required: 10 }, |
| 17 | + { fg: "#ffffff", bg: "#000000", name: "nav-text on nav-bg (solar)", required: 10 }, |
| 18 | + { fg: "#000000", bg: "#ffffff", name: "focus-ring on bg (solar)", required: 12 }, |
| 19 | + { fg: "#171717", bg: "#ffffff", name: "text on bg (light)", required: 0 }, |
| 20 | + { fg: "#6f5f48", bg: "#f7f4ee", name: "text-secondary on bg (light)", required: 0 }, |
| 21 | + { fg: "#0f766e", bg: "#f7f4ee", name: "primary on bg (light)", required: 0 }, |
| 22 | + { fg: "#ffffff", bg: "#0f766e", name: "primary-text on primary (light)", required: 0 }, |
| 23 | + { fg: "#ededed", bg: "#0a0a0a", name: "text on bg (dark)", required: 0 }, |
| 24 | + { fg: "#2dd4bf", bg: "#0a0a0a", name: "primary on bg (dark)", required: 0 }, |
| 25 | + { fg: "#0a0a0a", bg: "#2dd4bf", name: "primary-text on primary (dark)", required: 0 }, |
26 | 26 | ]; |
27 | 27 |
|
28 | 28 | function hexToRgb(hex) { |
@@ -53,27 +53,31 @@ function contrastRatio(hex1, hex2) { |
53 | 53 |
|
54 | 54 | let failures = 0; |
55 | 55 |
|
56 | | -for (const { fg, bg, name } of pairs) { |
| 56 | +for (const { fg, bg, name, required } of pairs) { |
57 | 57 | const ratio = contrastRatio(fg, bg); |
58 | 58 | const passesText = ratio >= 10.0; |
59 | 59 | const passesAAA = ratio >= 7.0; |
60 | | - const status = passesText |
61 | | - ? "PASS (10:1+)" |
62 | | - : passesAAA |
63 | | - ? "WARN (AAA 7:1+)" |
64 | | - : "FAIL"; |
65 | | - if (!passesText) failures++; |
| 60 | + const meetsRequired = required === 0 || ratio >= required; |
| 61 | + |
| 62 | + let status; |
| 63 | + if (required === 0) { |
| 64 | + status = "INFO"; |
| 65 | + } else if (metdsRequired) { |
| 66 | + status = "PASS"; |
| 67 | + } else { |
| 68 | + status = "FAIL"; |
| 69 | + } |
| 70 | + |
| 71 | + if (required > 0 && !meetsRequired) failures++; |
66 | 72 | console.log( |
67 | | - `${status.padEnd(12)} ${ratio.toFixed(2).padStart(5)}:1 ${name} (${fg} on ${bg})`, |
| 73 | + `${status.padEnd(8)} ${ratio.toFixed(2).padStart(5)}:1 ${name} (${fg} on ${bg})`, |
68 | 74 | ); |
69 | 75 | } |
70 | 76 |
|
71 | 77 | console.log(`\n---`); |
72 | 78 | if (failures === 0) { |
73 | | - console.log(`All ${pairs.length} pairs meet 10:1 minimum contrast.`); |
| 79 | + console.log(`All required contrast pairs meet minimum thresholds.`); |
74 | 80 | } else { |
75 | | - console.log( |
76 | | - `${failures} pair(s) below 10:1 threshold (but may still pass WCAG AAA 7:1).`, |
77 | | - ); |
| 81 | + console.log(`${failures} pair(s) below required threshold.`); |
78 | 82 | process.exitCode = 1; |
79 | 83 | } |
0 commit comments