const clipboard = navigator.clipboard; let app = new Vue({ el: '#app', data: { defaultInputs: [ "ccc", "#db2777aa", "rgb(64, 240, 18)", "hsla(240, 86.9%, 50.7%, 0.8)", ], inputBox: "ccc\n#4f46e5\n#db2777aa\n", showStatusMessage: false, showErrorMessage: false, hexRegex: /^\#?[a-f0-9]{3,9}/i, rgbRegex: /^rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)/i, rgbaRegex: /^rgba\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*(0(\.[0-9])?|1(\.0)?)\s*\)/i, hslRegex: /^hsl\(\s*\d{1,3}\s*,\s*\d{1,3}(\.[0-9])?%\s*,\s*\d{1,3}(\.[0-9])?%\s*\)/i, hslaRegex: /^hsla\(\s*\d{1,3}\s*,\s*\d{1,3}(\.[0-9])?%\s*,\s*\d{1,3}(\.[0-9])?%\s*,\s*(0(\.[0-9])?|1(\.0)?)\s*\)/i, convertedColors: [], }, beforeMount: function () { this.inputBox = this.defaultInputs.join("\n"); }, mounted: function () { this.batchConvert(); }, methods: { batchConvert: function () { this.convertedColors = []; // first attempt to split by new-line characters let inputArray = this.inputBox.split('\n'); let count = inputArray.length; for (let i = 0; i < count; i++) { // check for empty line, non hex(a)/rgb(a)/hsl(a) string let inputLine = inputArray[i].toLowerCase().trim(); if (inputLine.length === 0) { continue; } let converted = { error: false, raw: inputLine, hex: "", rgb: "", hsl: "", }; if (this.hexRegex.test(inputLine)) { let hexString = inputLine; // doing this just to add pound symbol for the table output // if it doesn't already exist and to allow the use of // the hex value without leading pound symbol // for conversion to other formats. hexString = hexString.replace('#', ''); converted.hex = "#" + hexString; // check if it has an alpha channel, and possibly shorthand if (hexString.length === 4 || hexString.length === 8) { rgb = this.hexaToRgba(hexString); converted.rgb = "rgba(" + rgb.red + ", " + rgb.green + ", " + rgb.blue + ", " + rgb.alpha + ")"; hsl = this.rgbaToHsla(rgb.red, rgb.green, rgb.blue, rgb.alpha); converted.hsl = "hsla(" + hsl.hue + ", " + hsl.saturation + "%, " + hsl.lightness + "%, " + hsl.alpha + ")"; } else { rgb = this.hexToRgb(hexString); converted.rgb = "rgb(" + rgb.red + ", " + rgb.green + ", " + rgb.blue + ")"; hsl = this.rgbToHsl(rgb.red, rgb.green, rgb.blue); converted.hsl = "hsl(" + hsl.hue + ", " + hsl.saturation + "%, " + hsl.lightness + "%)"; } } if (this.rgbRegex.test(inputLine)) { // extract the values for red, green, blue. let rgbStrArray = inputLine.split(','); let red = rgbStrArray[0].replace('rgb(', '').trim(); let green = rgbStrArray[1].trim(); let blue = rgbStrArray[2].replace(')', '').trim(); red = Number.parseInt(red); green = Number.parseInt(green); blue = Number.parseInt(blue); converted.hex = "#" + this.rgbToHex(red, green, blue); converted.rgb = "rgb(" + red + ", " + green + ", " + blue + ")"; let hsl = this.rgbToHsl(red, green, blue); converted.hsl = converted.hsl = "hsl(" + hsl.hue + ", " + hsl.saturation + "%, " + hsl.lightness + "%)"; } if (this.rgbaRegex.test(inputLine)) { // extract the values for red, green, blue, alpha. let rgbaStrArray = inputLine.split(','); let red = rgbaStrArray[0].replace('rgba(', '').trim(); let green = rgbaStrArray[1].trim(); let blue = rgbaStrArray[2].trim(); let alpha = rgbaStrArray[3].replace(')', '').trim(); red = Number.parseInt(red); green = Number.parseInt(green); blue = Number.parseInt(blue); converted.hex = "#" + this.rgbaToHexa(red, green, blue, alpha); converted.rgb = "rgba(" + red + ", " + green + ", " + blue + ", " + alpha + ")"; let hsl = this.rgbToHsl(red, green, blue); converted.hsl = "hsla(" + hsl.hue + ", " + hsl.saturation + "%, " + hsl.lightness + "%, " + alpha + ")"; } if (this.hslRegex.test(inputLine)) { // extract the values for hue, saturation, lightness. let hslStrArray = inputLine.split(','); let hue = hslStrArray[0].replace('hsl(', '').trim(); let saturation = hslStrArray[1].replace('%', '').trim(); let lightness = hslStrArray[2].replace('%', '').replace(')', '').trim(); converted.hex = "#" + this.hslToHex(hue, saturation, lightness); let rgb = this.hslToRgb(hue, saturation, lightness); converted.rgb = "rgb(" + rgb.red + ", " + rgb.green + ", " + rgb.blue + ")"; converted.hsl = "hsl(" + hue + ", " + saturation + "%, " + lightness + "%)"; } if (this.hslaRegex.test(inputLine)) { // extract the values for hue, saturation, lightness, alpha. let hslaStrArray = inputLine.split(','); let hue = hslaStrArray[0].replace('hsla(', '').trim(); let saturation = hslaStrArray[1].replace('%', '').trim(); let lightness = hslaStrArray[2].replace('%', '').trim(); let alpha = hslaStrArray[3].replace(')', '').trim(); converted.hex = "#" + this.hslaToHexa(hue, saturation, lightness, alpha); let rgb = this.hslaToRgba(hue, saturation, lightness, alpha); converted.rgb = "rgb(" + rgb.red + ", " + rgb.green + ", " + rgb.blue + ", " + alpha + ")"; converted.hsl = "hsla(" + hue + ", " + saturation + "%, " + lightness + "%, " + alpha + ")"; } this.convertedColors.push(converted); } }, // hex -> RGB hexToRgb: function (hexString) { let hex = 'ffffff'; if (hexString.length === 3) { hex = ''; hex += hexString.substr(2, 1) + hexString.substr(2, 1); hex += hexString.substr(1, 1) + hexString.substr(1, 1); hex += hexString.substr(0, 1) + hexString.substr(0, 1); } else { hex = hexString; } let bigint = Number.parseInt(hex, 16); let r = (bigint >> 16) & 255; let g = (bigint >> 8) & 255; let b = bigint & 255; return { "red": r, "green": g, "blue": b }; }, // hexa -> RGBa hexaToRgba: function (hexString) { let hex = 'ffffff'; let alphaHex = 'ff'; let alpha = 1; if (hexString.length === 4) { alphaHex = hexString.substr(3, 1) + hexString.substr(3, 1); hex = ''; hex += hexString.substr(2, 1) + hexString.substr(2, 1); hex += hexString.substr(1, 1) + hexString.substr(1, 1); hex += hexString.substr(0, 1) + hexString.substr(0, 1); } else { alphaHex = hexString.substr(6, 2); hex = hexString.substr(0, 6); } let rgb = this.hexToRgb(hex); alpha = Number.parseFloat((Number.parseInt(alphaHex, 16) / 255)).toFixed(1); return { "red": rgb.red, "green": rgb.green, "blue": rgb.blue, "alpha": alpha }; }, // hex -> HSL hexToHsl: function (hexString) { console.error('hex to HSL not implemented yet'); }, // hexa -> HSLa hexaToHsla: function (hexString) { console.error('hexa to HSLa not implemented yet'); }, // RGB -> hex rgbToHex: function (r, g, b) { let red = r.toString(16); let green = g.toString(16); let blue = b.toString(16); if (red.length === 1) { red = "0" + red; } if (green.length === 1) { green = "0" + green; } if (blue.length === 1) { blue = "0" + blue; } return "" + red + green + blue; }, // RGBa -> hexa rgbaToHexa: function (r, g, b, a) { let hex = this.rgbToHex(r, g, b); let alpha = Math.round(this.sanitizeAlphaFloat(a) * 255).toString(16); if (alpha.length == 1) { alpha = "0" + alpha; } return hex + alpha; }, // RGB -> HSL rgbToHsl: function (red, green, blue) { let hue = 0, saturation = 0, lightness = 0; let redFrac = Number.parseFloat(red / 255), greenFrac = Number.parseFloat(green / 255), blueFrac = Number.parseFloat(blue / 255); let channelMin = Math.min(redFrac, blueFrac, greenFrac), channelMax = Math.max(redFrac, blueFrac, greenFrac), delta = channelMax - channelMin; if (delta === 0) { hue = 0; } // Red is the maximum color else if (channelMax === redFrac) { hue = ((greenFrac - blueFrac) / delta) % 6; } // Green is the maximum color else if (channelMax === greenFrac) { hue = (blueFrac - redFrac) / delta + 2; } // Green is the maximum color else { hue = (redFrac - greenFrac) / delta + 4; } hue = Math.round(hue * 60); // Make negative hues positive behind 360° if (hue < 0) { hue += 360; } lightness = (channelMax + channelMin) / 2; if (delta === 0) { saturation = 0; } else { saturation = delta / (1 - Math.abs(2 * lightness - 1)); } lightness = +(lightness * 100).toFixed(1); saturation = +(saturation * 100).toFixed(1); return { "hue": hue, "saturation": saturation, "lightness": lightness }; }, // RGBa -> HSLa rgbaToHsla: function (r, g, b, al) { let hsl = this.rgbToHsl(r, g, b); hsl.alpha = this.sanitizeAlphaFloat(al); return hsl; }, // HSL -> hex hslToHex: function (hue, saturation, lightness) { let rgb = this.hslToRgb(hue, saturation, lightness); let red = rgb.red.toString(16); let green = rgb.green.toString(16); let blue = rgb.blue.toString(16); if (red.length === 1) { red = "0" + red; } if (green.length === 1) { green = "0" + green; } if (blue.length === 1) { blue = "0" + blue; } return "" + red + green + blue; }, // HSLa -> hexa hslaToHexa: function (hue, saturation, lightness, alpha) { let rgb = this.hslToRgb(hue, saturation, lightness); let red = rgb.red.toString(16); let green = rgb.green.toString(16); let blue = rgb.blue.toString(16); let alphaHex = Math.round(this.sanitizeAlphaFloat(alpha) * 255).toString(16); if (red.length === 1) { red = "0" + red; } if (green.length === 1) { green = "0" + green; } if (blue.length === 1) { blue = "0" + blue; } return "" + red + green + blue + alphaHex; }, // HSL -> RGB hslToRgb: function (hue, saturation, lightness) { if (hue === 360) { hue = 0; } if (hue < 0) { hue += 360; } saturation /= 100; lightness /= 100; let chroma = (1 - Math.abs(2 * lightness - 1)) * saturation, xComponent = chroma * (1 - Math.abs((hue / 60) % 2 - 1)), lightnessMatch = lightness - (chroma / 2), red = 0, green = 0, blue = 0; // set red and green if hue between 0 and 119 if (0 <= hue && hue < 60) { red = chroma; green = xComponent; } else if (60 <= hue && hue < 120) { red = xComponent; green = chroma; } // set green and blue if hue between 120 and 239 else if (120 <= hue && hue < 180) { green = chroma; blue = xComponent; } else if (180 <= hue && hue < 240) { green = xComponent; blue = chroma; } // set red and blue if hue between 0 and 119 else if (240 <= hue && hue < 300) { red = xComponent; blue = chroma; } else if (300 <= hue && hue < 360) { red = chroma; blue = xComponent; } red = Math.round((red + lightnessMatch) * 255); green = Math.round((green + lightnessMatch) * 255); blue = Math.round((blue + lightnessMatch) * 255); return { "red": red, "green": green, "blue": blue }; }, // HSLa -> RGBa hslaToRgba: function (hue, saturation, lightness, alpha) { let rgb = this.hslToRgb(hue, saturation, lightness); return { "red": rgb.red, "green": rgb.green, "blue": rgb.blue, "alpha": this.sanitizeAlphaFloat(alpha) }; }, // -------------------------------- // | helper methods // -------------------------------- // Normalize the alpha to between 0.0 and 1.0 // return single decimal place float value sanitizeAlphaFloat: function (alphaRaw) { let alpha = Number.parseFloat(1); if (alphaRaw >= 0 && alphaRaw <= 1) { alpha = Number.parseFloat(alphaRaw); } else if (alphaRaw < 0) { alpha = Number.parseFloat(0); } return alpha.toFixed(1); }, updateClipboard: function (text) { let _this = this; clipboard.writeText(text).then(() => { _this.showErrorMessage = false; _this.showStatusMessage = true; setTimeout(() => { _this.showStatusMessage = false; }, 1000); }) .catch(() => { _this.showStatusMessage = false; _this.showErrorMessage = true; setTimeout(() => { _this.showErrorMessage = false; }, 1000); }); }, }, });