blob: 369fed7b6ec09a47a70c478ab2f83025c4a5c6bc (
plain)
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
|
/**
* typing.js
* Typing animation for .hero-role / #typed element
*/
export function initTyping() {
'use strict';
const typedElement = document.getElementById('typed');
if (!typedElement) return;
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const phrasesJson = typedElement.getAttribute('data-phrases');
let phrases = [];
if (phrasesJson) {
try {
phrases = JSON.parse(phrasesJson);
} catch (e) {
console.warn('Failed to parse typing phrases:', e);
phrases = ['Security & Web Dev', 'WordPress Developer'];
}
}
if (!phrases.length) return;
let currentPhraseIndex = 0;
let currentCharIndex = 0;
let isDeleting = false;
function type() {
const phrase = phrases[currentPhraseIndex];
const speed = isDeleting ? 50 : 100;
if (isDeleting) {
currentCharIndex--;
} else {
currentCharIndex++;
}
typedElement.textContent = phrase.substring(0, currentCharIndex);
// Add cursor
if (!isDeleting && currentCharIndex === phrase.length) {
typedElement.innerHTML += '<span class="cursor"></span>';
} else if (isDeleting && currentCharIndex === 0) {
currentPhraseIndex = (currentPhraseIndex + 1) % phrases.length;
isDeleting = false;
setTimeout(type, 500);
return;
} else {
typedElement.innerHTML = phrase.substring(0, currentCharIndex) + '<span class="cursor"></span>';
}
if (!isDeleting && currentCharIndex === phrase.length) {
isDeleting = true;
setTimeout(type, 2000);
} else {
setTimeout(type, prefersReducedMotion ? 0 : speed);
}
}
if (prefersReducedMotion) {
// Just show the first phrase without animation
typedElement.textContent = phrases[0];
} else {
type();
}
}
|