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
|
const EmailUtils = {
getProfilePicture: async function (email, name) {
const gravatarUrl = await this.checkGravatar(email);
if (gravatarUrl) return gravatarUrl;
let domain = email.split('@')[1];
// Remove all subdomains from the domain
const domainParts = domain.split('.');
if (domainParts.length > 2) {
domainParts.shift();
domain = domainParts.join('.');
}
return `https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://${domain}&size=128`;
},
checkGravatar: async function (email) {
const hash = await this.sha256(email.toLowerCase().trim());
const testUrl = `https://www.gravatar.com/avatar/${hash}?s=128&d=404`;
return new Promise((resolve) => {
const img = new Image();
img.onload = () => resolve(testUrl);
img.onerror = () => resolve(null);
img.src = testUrl;
});
},
sha256: async function (message) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
},
getInitials: function (name, email) {
if (name && name !== email) {
const parts = name.trim().split(' ');
if (parts.length >= 2) {
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}
return name.substring(0, 2).toUpperCase();
}
return email.substring(0, 2).toUpperCase();
},
formatEmailDisplay: function (name, email, showAddress) {
if (!name || name === email) {
return email;
}
if (showAddress) {
return `${name} <${email}>`;
}
return name;
},
linkifyText: function (text) {
const urlRegex = /(https?:\/\/[^\s]+)/g;
const emailRegex = /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)/g;
return text
.replace(urlRegex, '<a href="$1" target="_blank" style="color: var(--accent-primary); text-decoration: underline;">$1</a>')
.replace(emailRegex, '<a href="mailto:$1" style="color: var(--accent-primary); text-decoration: underline;">$1</a>');
},
adjustContrast: function (container) {
const allElements = container.querySelectorAll('*');
allElements.forEach(el => {
const style = window.getComputedStyle(el);
const color = style.color;
const bgColor = style.backgroundColor;
const textLum = this.getLuminance(color);
const bgLum = this.getLuminance(bgColor);
const isTransparent = bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent';
let actualBgLum = bgLum;
if (isTransparent) {
let parent = el.parentElement;
while (parent && (window.getComputedStyle(parent).backgroundColor === 'rgba(0, 0, 0, 0)' ||
window.getComputedStyle(parent).backgroundColor === 'transparent')) {
parent = parent.parentElement;
}
if (parent) {
actualBgLum = this.getLuminance(window.getComputedStyle(parent).backgroundColor);
}
}
if (actualBgLum > 0.8 && textLum > 0.55) {
el.style.setProperty('color', '#000000', 'important');
} else if (actualBgLum < 0.3 && textLum < 0.45) {
el.style.setProperty('color', '#e8e8f0', 'important');
}
});
},
getLuminance: function (color) {
const rgb = color.match(/\d+/g);
if (!rgb || rgb.length < 3) return 1;
const [r, g, b] = rgb.map(val => {
const v = val / 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
};
|