-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
executable file
·128 lines (115 loc) · 3.72 KB
/
Copy pathscript.js
File metadata and controls
executable file
·128 lines (115 loc) · 3.72 KB
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
/**
* Contact reveal with light obfuscation.
* Email and phone never appear as plain text in the HTML source —
* they are stored reversed + base64 and assembled only after an
* explicit click, keeping them away from crawlers and scrapers.
*/
(() => {
const CHANNELS = {
email: {
enc: 'bW9jLmxpYW1nQDYwNTAyMGVzaXJlaGM=',
display: (v) => v,
openHref: (v) => `mailto:${v}`,
copyValue: (v) => v,
},
whatsapp: {
enc: 'NDExOTA2ODM0Nw==',
prefix: '44',
display: (v) => `+${v.slice(0, 2)} ${v.slice(2, 6)} ${v.slice(6, 9)} ${v.slice(9)}`,
openHref: (v) => `https://wa.me/${v}`,
copyValue: (v) => `+${v}`,
},
};
const decode = (channel) => {
const raw = atob(channel.enc).split('').reverse().join('');
return (channel.prefix || '') + raw;
};
const buildVCard = () => {
const email = decode(CHANNELS.email);
const phone = decode(CHANNELS.whatsapp);
return [
'BEGIN:VCARD',
'VERSION:3.0',
'FN:Coco',
`TEL;TYPE=CELL:+${phone}`,
`EMAIL:${email}`,
'URL:https://github.com/coco062',
'URL:https://www.linkedin.com/in/coco-tan-06bb1139b',
'NOTE:Finance & Business Analysis · Process Automation',
'END:VCARD',
].join('\r\n');
};
const panel = document.getElementById('reveal-panel');
const valueEl = document.getElementById('reveal-value');
const openLink = document.getElementById('reveal-open');
const copyBtn = document.getElementById('reveal-copy');
const vcardBtn = document.getElementById('reveal-vcard');
const noteEl = document.getElementById('reveal-note');
const buttons = {
email: document.getElementById('btn-email'),
whatsapp: document.getElementById('btn-whatsapp'),
};
if (!panel) return;
let active = null;
let flashTimer = null;
const flash = (message) => {
noteEl.textContent = message;
window.clearTimeout(flashTimer);
flashTimer = window.setTimeout(() => {
noteEl.textContent = '';
}, 2400);
};
const show = (key) => {
const channel = CHANNELS[key];
const value = decode(channel);
valueEl.textContent = channel.display(value);
openLink.href = channel.openHref(value);
panel.hidden = false;
noteEl.textContent = '';
active = key;
Object.entries(buttons).forEach(([k, btn]) =>
btn.setAttribute('aria-expanded', String(k === key))
);
};
const hide = () => {
panel.hidden = true;
active = null;
Object.values(buttons).forEach((btn) => btn.setAttribute('aria-expanded', 'false'));
};
Object.entries(buttons).forEach(([key, btn]) =>
btn.addEventListener('click', () => (active === key ? hide() : show(key)))
);
copyBtn.addEventListener('click', async () => {
if (!active) return;
const channel = CHANNELS[active];
const value = channel.copyValue(decode(channel));
try {
await navigator.clipboard.writeText(value);
flash('Copied.');
} catch {
flash(value);
}
});
vcardBtn.addEventListener('click', () => {
const blob = new Blob([buildVCard()], { type: 'text/vcard;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'coco.vcf';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
flash('Contact card downloaded.');
});
const reachLink = document.getElementById('callout-reach');
if (reachLink) {
reachLink.addEventListener('click', (event) => {
event.preventDefault();
show('email');
buttons.email.scrollIntoView({ behavior: 'smooth', block: 'center' });
});
}
const yearEl = document.getElementById('year');
if (yearEl) yearEl.textContent = String(new Date().getFullYear());
})();