-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
96 lines (88 loc) · 3.02 KB
/
Copy pathscript.js
File metadata and controls
96 lines (88 loc) · 3.02 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
// Helpers
const $ = (sel, scope = document) => scope.querySelector(sel);
const $$ = (sel, scope = document) => Array.from(scope.querySelectorAll(sel));
// Year
$('#year').textContent = new Date().getFullYear();
// Smooth scroll (extra – CSS already does it, this ensures older browsers)
$$('.nav-link').forEach(a => {
a.addEventListener('click', e => {
e.preventDefault();
const id = a.getAttribute('href');
document.querySelector(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
});
});
// ScrollSpy – highlight active link
const sections = $$('.section');
const navLinks = $$('.nav-link');
const spy = new IntersectionObserver(entries => {
entries.forEach(entry => {
const id = entry.target.getAttribute('id');
const link = $(`.nav-link[href="#${id}"]`);
if (entry.isIntersecting) {
navLinks.forEach(l => l.classList.remove('active'));
link?.classList.add('active');
}
});
}, { threshold: 0.6 });
sections.forEach(sec => spy.observe(sec));
// Animate skill lines on view
const lineObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('show');
}
});
}, { threshold: 0.4 });
$$('.line[data-animate]').forEach(el => lineObserver.observe(el));
// Subtle 3D tilt on project cards
$$('.card.tilt').forEach(card => {
const strength = 10; // degrees
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const rx = ((y / rect.height) - 0.5) * -strength;
const ry = ((x / rect.width) - 0.5) * strength;
card.style.transform = `rotateX(${rx}deg) rotateY(${ry}deg) translateY(-6px)`;
});
card.addEventListener('mouseleave', () => {
card.style.transform = '';
});
});
// Parallax shapes follow cursor slightly
const layer = $('.shape-layer');
if (layer) {
window.addEventListener('mousemove', (e) => {
const { innerWidth:w, innerHeight:h } = window;
const x = (e.clientX / w - 0.5) * 16;
const y = (e.clientY / h - 0.5) * 16;
$$('.blob, .geo', layer).forEach((el, i) => {
const damp = (i + 4);
el.style.transform = `translate(${x/damp}px, ${y/damp}px)`;
});
});
}
// Theme toggle (dark <-> light)
const root = document.documentElement;
const toggle = $('#themeToggle');
const lightVars = {
'--bg':'#f6f7fb',
'--card':'#ffffff',
'--text':'#0c1020',
'--muted':'#4b5565',
'--line':'rgba(0,0,0,.08)',
'--glass':'rgba(0,0,0,.04)',
};
const darkVars = null; // default from CSS
let isLight = false;
toggle.addEventListener('click', () => {
isLight = !isLight;
if (isLight) {
for (const [k,v] of Object.entries(lightVars)) root.style.setProperty(k, v);
toggle.textContent = '☀️';
} else {
// reset to dark (remove overrides)
for (const k of Object.keys(lightVars)) root.style.removeProperty(k);
toggle.textContent = '🌙';
}
});