-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
108 lines (94 loc) · 3.42 KB
/
script.js
File metadata and controls
108 lines (94 loc) · 3.42 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
// Project Filtering
document.addEventListener('DOMContentLoaded', () => {
initProjectFilters();
initTheme();
initScrollAnimations();
initBackgroundStars();
});
function initBackgroundStars() {
const container = document.querySelector('.bg-stars');
if (!container) return;
const count = 55;
const starClasses = ['star', 'star star--dim', 'star star--accent'];
const dimWeight = 0.5;
const accentWeight = 0.2;
for (let i = 0; i < count; i++) {
const star = document.createElement('span');
let cls = 'star';
const r = Math.random();
if (r < accentWeight) cls = 'star star--accent';
else if (r < accentWeight + dimWeight) cls = 'star star--dim';
star.className = cls;
star.style.left = Math.random() * 100 + '%';
star.style.top = Math.random() * 100 + '%';
star.style.animationDelay = Math.random() * 3 + 's';
container.appendChild(star);
}
}
function initProjectFilters() {
const filterButtons = document.querySelectorAll('.filter-btn');
const projectCards = document.querySelectorAll('.project-card');
filterButtons.forEach(button => {
button.addEventListener('click', () => {
// Remove active class from all buttons
filterButtons.forEach(btn => btn.classList.remove('active'));
// Add active class to clicked button
button.classList.add('active');
const filter = button.getAttribute('data-filter');
projectCards.forEach(card => {
const category = card.getAttribute('data-category');
if (filter === 'all' || category === filter) {
card.style.display = 'flex';
setTimeout(() => {
card.style.opacity = '1';
card.style.transform = 'translateY(0)';
}, 10);
} else {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
setTimeout(() => {
card.style.display = 'none';
}, 300);
}
});
});
});
// Initialize cards with transition
projectCards.forEach(card => {
card.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
card.style.display = 'flex';
card.style.opacity = '1';
});
}
function setTheme(theme) {
const root = document.documentElement;
root.setAttribute('data-theme', theme);
try {
localStorage.setItem('theme', theme);
} catch (_) {}
}
function initTheme() {
let preferred = 'dark';
try {
const saved = localStorage.getItem('theme');
if (saved === 'light' || saved === 'dark') preferred = saved;
} catch (_) {}
setTheme(preferred);
}
function initScrollAnimations() {
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible');
observer.unobserve(entry.target); // Only animate once
}
});
}, observerOptions);
const animatedElements = document.querySelectorAll('.animate-on-scroll');
animatedElements.forEach(el => observer.observe(el));
}