(function(){ function parseColor(hex) { if (!hex) return [255, 255, 255]; let c = hex.replace('#', ''); if (c.length === 3) c = c.split('').map(x => x + x).join(''); const num = parseInt(c, 16); return [(num >> 16) & 255, (num >> 8) & 255, num & 255]; } const toHex = v => v.toString(16).padStart(2, '0'); function hexToRgba(hex, a = 1) { const [r, g, b] = parseColor(hex); return `rgba(${r},${g},${b},${a})`; } function getContrastColor(hex) { const [r, g, b] = parseColor(hex); const yiq = (r * 299 + g * 587 + b * 114) / 1000; return yiq >= 128 ? '#000' : '#fff'; } function lightenColor(hex, p) { const [r, g, b] = parseColor(hex).map(v => Math.min(255, Math.round(v + (255 - v) * p)) ); return '#' + [r, g, b].map(toHex).join(''); } function getHumanDiff(d1, d2) { let start = d1 < d2 ? d1 : d2; let end = d1 < d2 ? d2 : d1; let years = end.getUTCFullYear() - start.getUTCFullYear(); let months = end.getUTCMonth() - start.getUTCMonth(); let days = end.getUTCDate() - start.getUTCDate(); if (days < 0) { months--; let prevMonthDays = new Date(Date.UTC( end.getUTCFullYear(), end.getUTCMonth(), 0 )).getUTCDate(); days += prevMonthDays; } if (months < 0) { years--; months += 12; } let aligned = new Date(Date.UTC( start.getUTCFullYear() + years, start.getUTCMonth() + months, start.getUTCDate() + days, start.getUTCHours(), start.getUTCMinutes(), start.getUTCSeconds() )); let diffMs = end.getTime() - aligned.getTime(); if (diffMs < 0) { diffMs += 24 * 3600e3; if (days > 0) { days--; } else { months--; if (months < 0) { years--; months += 12; } days = new Date(Date.UTC( end.getUTCFullYear(), end.getUTCMonth(), 0 )).getUTCDate(); } } let hours = Math.floor(diffMs / 3600e3); diffMs -= hours * 3600e3; let minutes = Math.floor(diffMs / 60e3); diffMs -= minutes * 60e3; let seconds = Math.floor(diffMs / 1e3); return { years, months, days, hours, minutes, seconds }; } window.Utils = { parseColor, hexToRgba, getContrastColor, lightenColor, getHumanDiff }; })();