-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
111 lines (95 loc) · 3.3 KB
/
main.js
File metadata and controls
111 lines (95 loc) · 3.3 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
/* =========================
Utility helpers
========================= */
const $ = (selector, scope = document) => scope.querySelector(selector);
const $$ = (selector, scope = document) =>
Array.from(scope.querySelectorAll(selector));
/* =========================
Active navigation state
========================= */
(function setActiveNavLink() {
const currentPage = window.location.pathname.split("/").pop().toLowerCase();
$$("nav a").forEach(link => {
const href = link.getAttribute("href").toLowerCase();
if (href === currentPage || (currentPage === "" && href === "index.html")) {
link.setAttribute("aria-current", "page");
}
});
})();
/* =========================
Smooth scroll for in-page links
========================= */
$$('a[href^="#"]').forEach(anchor => {
anchor.addEventListener("click", e => {
const targetId = anchor.getAttribute("href");
const target = $(targetId);
if (!target) return;
e.preventDefault();
target.scrollIntoView({ behavior: "smooth" });
target.setAttribute("tabindex", "-1");
target.focus({ preventScroll: true });
});
});
/* =========================
Intro fade-in animation
========================= */
(function introFadeIn() {
const intro = $("#intro");
if (!intro) return;
intro.style.opacity = "0";
intro.style.transform = "translateY(16px)";
requestAnimationFrame(() => {
intro.style.transition = "opacity 600ms ease, transform 600ms ease";
intro.style.opacity = "1";
intro.style.transform = "translateY(0)";
});
})();
/* =========================
Project card hover (keyboard-safe)
========================= */
$$("#projects li").forEach(card => {
card.setAttribute("tabindex", "0");
card.addEventListener("focus", () => {
card.classList.add("is-focused");
});
card.addEventListener("blur", () => {
card.classList.remove("is-focused");
});
});
/* =========================
Footer year auto-update
========================= */
(function updateFooterYear() {
const footer = $("footer");
if (!footer) return;
const year = new Date().getFullYear();
footer.innerHTML = footer.innerHTML.replace(/\d{4}/, year);
})();
/* =========================
Hamburger menu logic
========================= */
(function hamburgerMenu() {
const toggle = document.querySelector(".nav-toggle");
const menu = document.querySelector("#nav-menu");
if (!toggle || !menu) return;
toggle.addEventListener("click", () => {
const isOpen = toggle.getAttribute("aria-expanded") === "true";
toggle.setAttribute("aria-expanded", String(!isOpen));
menu.classList.toggle("open");
});
// Close menu on Escape
document.addEventListener("keydown", e => {
if (e.key === "Escape" && menu.classList.contains("open")) {
menu.classList.remove("open");
toggle.setAttribute("aria-expanded", "false");
toggle.focus();
}
});
// Close menu when clicking a link (mobile UX)
menu.querySelectorAll("a").forEach(link => {
link.addEventListener("click", () => {
menu.classList.remove("open");
toggle.setAttribute("aria-expanded", "false");
});
});
})();