-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathanimations.js
More file actions
129 lines (114 loc) · 4.08 KB
/
animations.js
File metadata and controls
129 lines (114 loc) · 4.08 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
129
// Scroll Animation Observer
const observerOptions = {
threshold: 0.1,
rootMargin: "0px 0px -50px 0px"
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-in');
}
});
}, observerOptions);
// TypeWriter class
class TypeWriter {
constructor(element, text, speed = 100) {
this.element = element;
this.text = text;
this.speed = speed;
this.index = 0;
this.type();
}
type() {
if (this.index < this.text.length) {
this.element.textContent += this.text.charAt(this.index);
this.index++;
setTimeout(() => this.type(), this.speed);
} else {
this.element.classList.add('typing-complete');
}
}
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', () => {
// Scroll animations
const sections = document.querySelectorAll('section');
sections.forEach(section => {
section.classList.add('animate-on-scroll');
observer.observe(section);
});
// Skill cards stagger
const skillCards = document.querySelectorAll('.skill-card');
skillCards.forEach((card, index) => {
card.classList.add('animate-on-scroll');
card.style.transitionDelay = `${index * 0.1}s`;
observer.observe(card);
});
// Project cards stagger
const projectCards = document.querySelectorAll('.project-card');
projectCards.forEach((card, index) => {
card.classList.add('animate-on-scroll');
card.style.transitionDelay = `${index * 0.15}s`;
observer.observe(card);
});
// Stat items stagger
const statItems = document.querySelectorAll('.stat-item');
statItems.forEach((item, index) => {
item.classList.add('animate-on-scroll');
item.style.transitionDelay = `${index * 0.1}s`;
observer.observe(item);
});
// Contact items stagger
const contactItems = document.querySelectorAll('.contact-item');
contactItems.forEach((item, index) => {
item.classList.add('animate-on-scroll');
item.style.transitionDelay = `${index * 0.1}s`;
observer.observe(item);
});
// Typing effect for hero subtitle
const subtitle = document.querySelector('.subtitle');
if (subtitle) {
const text = subtitle.textContent;
subtitle.textContent = '';
setTimeout(() => {
new TypeWriter(subtitle, text, 50);
}, 500);
}
// Skills carousel - touch scroll with auto-resume
const track = document.getElementById('skillsTrack');
if (track) {
// Mouse hover pause
track.addEventListener('mouseenter', () => track.classList.add('paused'));
track.addEventListener('mouseleave', () => track.classList.remove('paused'));
// Touch/drag - pause and allow manual scroll
let resumeTimer;
const pauseAutoScroll = () => {
track.classList.add('paused');
clearTimeout(resumeTimer);
resumeTimer = setTimeout(() => {
track.classList.remove('paused');
}, 2000);
};
track.addEventListener('touchstart', pauseAutoScroll, { passive: true });
track.addEventListener('touchmove', pauseAutoScroll, { passive: true });
track.addEventListener('mousedown', pauseAutoScroll);
}
// Section title reveal animation
const titleObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('title-revealed');
}
});
}, { threshold: 0.5 });
document.querySelectorAll('.section-title').forEach(title => {
titleObserver.observe(title);
});
// Loading state
document.body.classList.add('loaded');
document.body.style.opacity = '0';
document.body.style.transition = 'opacity 0.5s ease';
setTimeout(() => {
document.body.style.opacity = '1';
}, 100);
});