about summary refs log tree commit diff stats
path: root/html/ccc/index.html
blob: 5d3b28d2fe007e64b94643456296d80c9e629963 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Color Contrast Checker</title>
    <style>
        body { font-family: Arial, sans-serif; padding: 20px; }
        .color-input { margin-bottom: 10px; width: 100%; height: 100px; }
        .color-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
        .color-box { padding: 10px; text-align: center; border: 1px solid #ccc; }
        .hidden { display: none; }
        .form-controls { display: flex; justify-content: space-between; align-items: center; }
        .checkbox-controls { display: flex; gap: 20px; align-items: center; }
    </style>
</head>
<body>
    <header>
        <h1>What color combinations are accessible?</h1>
    </header>
    <main>
        <form id="colorForm" onsubmit="event.preventDefault(); updateColors();">
            <label for="colors">Enter hex color codes (comma or newline-separated):</label>
            <textarea id="colors" class="color-input" required></textarea>
            <div class="form-controls">
                <button type="submit">Check Contrast</button>
                <div class="checkbox-controls">
                    <label><input type="checkbox" id="toggleFails" onchange="updateVisibility()"> Hide failing pairs</label>
                    <label><input type="checkbox" id="sortContrast" onchange="updateColors()"> Sort by contrast</label>
                    <button type="button" onclick="shareColors()">Share Palette</button>
                </div>
            </div>
        </form>
        <br>
        <br>
        <section id="results" class="color-grid" aria-live="polite"></section>
    </main>
    <footer>
        <p>Color Contrast Checker - A tool to help you find accessible color combinations.</p>
    </footer>
    
    <script>
        window.addEventListener('load', () => {
            const urlParams = new URLSearchParams(window.location.search);
            const colors = urlParams.get('colors');
            if (colors) {
                document.getElementById('colors').value = decodeURIComponent(colors);
                updateColors();
            }
        });

        function shareColors() {
            const colors = document.getElementById('colors').value;
            if (!colors) return;
            
            const encodedColors = encodeURIComponent(colors);
            const url = `${window.location.origin}${window.location.pathname}?colors=${encodedColors}`;
            
            // Copy to clipboard
            navigator.clipboard.writeText(url).then(() => {
                alert('Share link copied to clipboard!');
            }).catch(() => {
                // Fallback if clipboard API fails
                prompt('Copy this share link:', url);
            });
        }

        function getContrastRatio(c1, c2) {
            function luminance(r, g, b) {
                let a = [r, g, b].map(v => {
                    v /= 255;
                    return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
                });
                return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
            }
            let rgb1 = c1.match(/\w\w/g).map(x => parseInt(x, 16));
            let rgb2 = c2.match(/\w\w/g).map(x => parseInt(x, 16));
            let lum1 = luminance(...rgb1);
            let lum2 = luminance(...rgb2);
            return (Math.max(lum1, lum2) + 0.05) / (Math.min(lum1, lum2) + 0.05);
        }

        function getWCAGLevel(contrast) {
            if (contrast >= 7) return "AAA";
            if (contrast >= 4.5) return "AA";
            return "Fail";
        }

        function createColorBox(color1, color2, contrast, level, accessible, showGlow) {
            const classes = ["color-box"];
            if (!accessible) classes.push("failing");
            if (level === "AAA" && showGlow) classes.push("glowing-border");
            
            return `
                <div class="${classes.join(' ')}" style="background: ${color1}; color: ${color2};">
                    ${color1} on ${color2}<br>
                    Ratio: ${contrast} ${accessible ? "✅" : "❌"}<br>
                    WCAG: ${level}
                </div>
            `;
        }

        function updateColors() {
            const input = document.getElementById("colors").value;
            const colors = input.split(/[\n,]+/).map(c => c.trim()).filter(c => c);
            const results = document.getElementById("results");

            const colorCombinations = colors.flatMap((color1, i) => 
                colors.slice(i + 1).map(color2 => {
                    const contrast = getContrastRatio(color1, color2).toFixed(2);
                    const level = getWCAGLevel(contrast);
                    const accessible = level !== "Fail";
                    return { color1, color2, contrast, level, accessible };
                })
            );

            const sortByContrast = document.getElementById("sortContrast").checked;
            if (sortByContrast) {
                colorCombinations.sort((a, b) => b.contrast - a.contrast);
            }

            const colorBoxes = colorCombinations.map(({ color1, color2, contrast, level, accessible }) => {
                return createColorBox(color1, color2, contrast, level, accessible, false);
            });

            results.innerHTML = colorBoxes.join('');
            updateVisibility();
        }

        function updateVisibility() {
            let hideFails = document.getElementById("toggleFails").checked;
            
            document.querySelectorAll(".failing").forEach(box => {
                box.style.display = hideFails ? "none" : "block";
            });
        }
    </script>
</body>
</html>