import ColorScheme from "color-scheme"; type ColorScheme = { primary: string; hover: string; active: string }; export function blendWithBlack(hex: string, blackPercentage: number): string { // Remove the leading '#' if present hex = hex.replace(/^#/, ""); // Parse the hex color let r = parseInt(hex.substring(0, 2), 16); let g = parseInt(hex.substring(2, 4), 16); let b = parseInt(hex.substring(4, 6), 16); // Calculate the mix factor for the color let colorPercentage = 1 - blackPercentage / 100; // Mix the color with black r = Math.floor(r * colorPercentage); g = Math.floor(g * colorPercentage); b = Math.floor(b * colorPercentage); // Ensure the new RGB values are within the valid range r = Math.max(0, Math.min(255, r)); g = Math.max(0, Math.min(255, g)); b = Math.max(0, Math.min(255, b)); // Convert the RGB values back to a hex string const newHex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`; return newHex; } export function blendWithWhite(hex: string, whitePercentage: number): string { // Remove the leading '#' if present hex = hex.replace(/^#/, ""); // Parse the hex color let r = parseInt(hex.substring(0, 2), 16); let g = parseInt(hex.substring(2, 4), 16); let b = parseInt(hex.substring(4, 6), 16); // Calculate the mix factor for the color let colorPercentage = 1 - whitePercentage / 100; // Mix the color with white r = Math.floor(r * colorPercentage + (255 * whitePercentage) / 100); g = Math.floor(g * colorPercentage + (255 * whitePercentage) / 100); b = Math.floor(b * colorPercentage + (255 * whitePercentage) / 100); // Ensure the new RGB values are within the valid range r = Math.max(0, Math.min(255, r)); g = Math.max(0, Math.min(255, g)); b = Math.max(0, Math.min(255, b)); // Convert the RGB values back to a hex string const newHex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`; return newHex; } function hexToRgb(hex) { hex = hex.replace(/^#/, ""); if (hex.length === 3) { hex = hex .split("") .map((char) => char + char) .join(""); } const bigint = parseInt(hex, 16); const r = (bigint >> 16) & 255; const g = (bigint >> 8) & 255; const b = bigint & 255; return { r, g, b }; } function relativeLuminance(r, g, b) { const toLinear = (c) => { c /= 255; return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); }; r = toLinear(r); g = toLinear(g); b = toLinear(b); return 0.2126 * r + 0.7152 * g + 0.0722 * b; } // Function to calculate contrast ratio function contrastRatio(l1, l2) { return l1 > l2 ? (l1 + 0.05) / (l2 + 0.05) : (l2 + 0.05) / (l1 + 0.05); } // Function to convert RGB to HSL function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b); let h, s, l = (max + min) / 2; if (max === min) { h = s = 0; // achromatic } else { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h, s, l }; } // Function to convert HSL to RGB function hslToRgb(h, s, l) { let r, g, b; if (s === 0) { r = g = b = l; // achromatic } else { const hue2rgb = (p, q, t) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); } return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255), }; } // Function to convert RGB to HEX function rgbToHex(r, g, b) { return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); } // Function to ensure the contrast ratio meets the required threshold export function getHighContrastColor(hex, minContrastRatio = 3.7) { // Convert hex to RGB let { r, g, b } = hexToRgb(hex); // Convert RGB to HSL let { h, s, l } = rgbToHsl(r, g, b); let secondaryLuminance; let secondaryHex; // Adjust lightness for high contrast const primaryLuminance = relativeLuminance(r, g, b); let steps = 20; // Number of steps to find a valid color for (let i = 0; i <= steps; i++) { // Try both lighter and darker adjustments let lightnessAdjust = (i / steps) * 1.2; // Lighter step let newLighterL = Math.min(1, l + lightnessAdjust); let { r: lr, g: lg, b: lb } = hslToRgb(h, s, newLighterL); secondaryLuminance = relativeLuminance(lr, lg, lb); if ( contrastRatio(primaryLuminance, secondaryLuminance) >= minContrastRatio ) { secondaryHex = rgbToHex(lr, lg, lb); return secondaryHex; } lightnessAdjust = (i / steps) * 1.2; // Darker step let newDarkerL = Math.max(0, l - lightnessAdjust); let { r: dr, g: dg, b: db } = hslToRgb(h, s, newDarkerL); secondaryLuminance = relativeLuminance(dr, dg, db); if ( contrastRatio(primaryLuminance, secondaryLuminance) >= minContrastRatio ) { secondaryHex = rgbToHex(dr, dg, db); return secondaryHex; } } // Return the secondary color with the adjusted lightness if no exact match found return secondaryHex || rgbToHex(r, g, b); } export function getColorPaletteByVariation(primaryColor: string) { const scheme = new ColorScheme(); scheme.from_hex(primaryColor?.split(`#`)[1]).scheme("mono"); return scheme.colors() as string[]; } export function hexToRGBAHex(alpha: number, hex?: string) { // Remove the hash symbol if it is present if (!hex) return; hex = hex.replace(/^#/, ""); // Ensure the alpha is between 0 and 1 if (alpha < 0) alpha = 0; if (alpha > 1) alpha = 1; // Convert alpha to 255 scale and then to hex let a = Math.round(alpha * 255); let alphaHex = a.toString(16).padStart(2, "0"); // Return the hex color with alpha return `#${hex}${alphaHex}`; } export default function getStyles( primaryColors: ColorScheme, secondaryColors: ColorScheme, primaryColorPalette: string[], isBlackOrWhite?: boolean ) { const bgColor = isBlackOrWhite ? "dadada" : primaryColorPalette[2]; return ` #compensation-snippet .bg-interactive-primary-default, #compensation-snippet .bg-brand-primary{ background-color: ${primaryColors?.primary} !important; } #compensation-snippet .bg-interactive-primary-default:hover{ background-color: ${primaryColors?.hover} !important; } #compensation-snippet .bg-interactive-primary-default:active{ background-color: ${primaryColors?.active} !important; } #compensation-snippet .bg-interactive-secondary-default{ background-color: ${secondaryColors.primary}; } #compensation-snippet .bg-interactive-secondary-default:hover{ background-color: ${secondaryColors.hover}; } #compensation-snippet .bg-interactive-secondary-default:active{ background-color: ${secondaryColors.active}; } #compensation-snippet .bg-brand-primary-20{ background-color: #${bgColor}; } #compensation-snippet .bg-neutral-very-light{ background-color: #${bgColor} !important; } #compensation-snippet .text-interactive-primary-default, #compensation-snippet .text-brand-primary{ color: ${primaryColors.primary}; } #compensation-snippet .text-akzent-zwei{ color: ${primaryColors.primary}; } #compensation-snippet .text-interactive-secondary-default{ color: ${secondaryColors.primary}; } #compensation-snippet .border-brand-primary, #compensation-snippet .border-interactive-primary-default{ border-color: ${primaryColors.primary} !important; } #compensation-snippet .border-interactive-primary-pressed{ border-color: ${primaryColors.hover}; } #compensation-snippet .border-interactive-primary-pressed{ border-color: ${primaryColors.active}; } #compensation-snippet .border-interactive-secondary-pressed{ border-color: ${secondaryColors.active} } #compensation-snippet .border-akzent-zwei{ border-color: ${primaryColors.primary}; } #compensation-snippet .fill-white{ fill: white; } #compensation-snippet .fill-brand-primary, #compensation-snippet .fill-interactive-primary-default{ fill: ${primaryColors.primary}; } #compensation-snippet .ring-interactive-primary-focus::before { --tw-ring-color: ${primaryColors.primary}; } #compensation-snippet .input-state-default label { color: ${primaryColors.primary}; } #compensation-snippet .input-state-default svg { fill: ${primaryColors.primary} !important; } #compensation-snippet .input-state-default { border-color: ${primaryColors.primary}; } #compensation-snippet .input-state-active label { color: ${primaryColors.primary}; } #compensation-snippet .input-state-active svg { fill: ${primaryColors.primary}; } #compensation-snippet .input-state-active { border-color: ${primaryColors.primary}; } #compensation-snippet .input-state-active input { background-color: #${bgColor} } #compensation-snippet input[type='radio']:checked, #compensation-snippet input[type='checkbox']:checked{ background-color: ${primaryColors.primary} !important; } #compensation-snippet input[type='radio']:active, #compensation-snippet input[type='radio']:focus, #compensation-snippet input[type='radio']:focus-visible{ --tw-ring-color: ${primaryColors.primary}; } #compensation-snippet input[type='checkbox']{ background-color: inherit; } #compensation-snippet input[type='checkbox']:active, #compensation-snippet input[type='checkbox']:focus, #compensation-snippet input[type='checkbox']:focus-visible{ --tw-ring-color: #${bgColor} !important; box-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color) !important; } #compensation-snippet input:-webkit-autofill, #compensation-snippet input:-webkit-autofill:hover, #compensation-snippet input:-webkit-autofill:focus, #compensation-snippet input:-webkit-autofill:active{ transition: background-color 5000s ease-in-out 0s; box-shadow: inset 0 0 20px 20px #${bgColor}; } `; }