-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
103 lines (91 loc) · 3.59 KB
/
script.js
File metadata and controls
103 lines (91 loc) · 3.59 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
document.addEventListener('DOMContentLoaded', () => {
const html = document.documentElement;
const themeToggle = document.getElementById('themeToggle');
const metaThemeColor = document.querySelector('meta[name="theme-color"]');
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
// THEME — load & apply
const saved = localStorage.getItem('theme');
const initialTheme = saved || (prefersDark ? 'dark' : 'light');
applyTheme(initialTheme);
function applyTheme(theme) {
html.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
if (themeToggle) {
const icon = themeToggle.querySelector('i');
if (icon) {
icon.classList.toggle('fa-moon', theme === 'light');
icon.classList.toggle('fa-sun', theme === 'dark');
}
}
if (metaThemeColor) {
metaThemeColor.setAttribute('content', theme === 'dark' ? '#0f172a' : '#1e40af');
}
}
if (themeToggle) {
themeToggle.addEventListener('click', () => {
const next = html.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
applyTheme(next);
});
}
// NAVBAR scroll state
const navbar = document.querySelector('.navbar');
const setNavbarState = () => {
if (!navbar) return;
if (window.scrollY > 20) navbar.classList.add('scrolled');
else navbar.classList.remove('scrolled');
};
setNavbarState();
window.addEventListener('scroll', setNavbarState);
// Smooth scroll
document.querySelectorAll('a[href^="#"]:not([data-bs-toggle])').forEach(anchor => {
anchor.addEventListener('click', (e) => {
const id = anchor.getAttribute('href');
if (!id || id === '#') return;
const target = document.querySelector(id);
if (!target) return;
e.preventDefault();
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
// collapse navbar on mobile after click
const navCollapse = document.getElementById('navbarNav');
if (navCollapse && navCollapse.classList.contains('show')) {
const bsCollapse = bootstrap.Collapse.getInstance(navCollapse) || new bootstrap.Collapse(navCollapse, { toggle: false });
bsCollapse.hide();
}
});
});
// Active link highlight
const sections = Array.from(document.querySelectorAll('section[id]'));
const navLinks = document.querySelectorAll('.nav-link');
const onScrollActive = () => {
let currentId = '';
const offset = 150; // slightly adjusted for accuracy
sections.forEach(sec => {
if (window.scrollY + offset >= sec.offsetTop) currentId = sec.id;
});
navLinks.forEach(link => link.classList.toggle('active', link.getAttribute('href') === `#${currentId}`));
};
onScrollActive();
window.addEventListener('scroll', onScrollActive);
// Reveal on scroll
const revealEls = document.querySelectorAll('.reveal');
const io = ('IntersectionObserver' in window)
? new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('in-view');
io.unobserve(entry.target);
}
});
}, { threshold: 0.1 })
: null;
revealEls.forEach(el => { if (io) io.observe(el); else el.classList.add('in-view'); });
// Lazy image polish
document.querySelectorAll('img[loading="lazy"]').forEach(img => {
const done = () => img.classList.add('lazy-done');
if (img.complete) done();
else img.addEventListener('load', done, { once: true });
});
// Footer year
const y = document.getElementById('year');
if (y) y.textContent = new Date().getFullYear();
});