Repository navigation
Expand file tree
/
Copy pathmain.js
More file actions
109 lines (95 loc) · 2.9 KB
/
Copy pathmain.js
File metadata and controls
109 lines (95 loc) · 2.9 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
/* HELIX site interactions — dependency-free, restrained, accessible.
Sections:
1. Preloader (once per session, CSS-driven fallback)
2. Scroll reveal
3. Animated counters
All effects honor prefers-reduced-motion. */
(function () {
"use strict";
const REDUCE = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
/* ---------- 1. Preloader ---------- */
(function preloader() {
const el = document.querySelector(".preloader");
if (!el) return;
const dismiss = function () {
el.classList.add("preloader--hide");
window.setTimeout(function () {
el.remove();
}, 700);
};
// Already seen this session, or reduced motion: skip the reveal entirely.
if (REDUCE || sessionStorage.getItem("helix-intro") === "1") {
el.remove();
return;
}
sessionStorage.setItem("helix-intro", "1");
el.classList.add("preloader--active");
el.addEventListener("click", dismiss);
window.setTimeout(dismiss, 600);
})();
/* ---------- 2. Scroll reveal ---------- */
(function reveal() {
const items = document.querySelectorAll("[data-reveal]");
if (!items.length) return;
if (REDUCE || !("IntersectionObserver" in window)) {
items.forEach(function (el) {
el.classList.add("is-visible");
});
return;
}
const io = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("is-visible");
io.unobserve(entry.target);
}
});
},
{ threshold: 0.12, rootMargin: "0px 0px -8% 0px" }
);
items.forEach(function (el) {
io.observe(el);
});
})();
/* ---------- 3. Animated counters ---------- */
(function counters() {
const nums = document.querySelectorAll("[data-count]");
if (!nums.length) return;
function run(el) {
const target = parseInt(el.getAttribute("data-count"), 10) || 0;
if (REDUCE) {
el.textContent = String(target);
return;
}
const dur = 1100;
const start = performance.now();
function tick(now) {
const t = Math.min(1, (now - start) / dur);
const eased = 1 - Math.pow(1 - t, 3); // easeOutCubic
el.textContent = String(Math.round(eased * target));
if (t < 1) requestAnimationFrame(tick);
else el.textContent = String(target);
}
requestAnimationFrame(tick);
}
if (!("IntersectionObserver" in window)) {
nums.forEach(run);
return;
}
const io = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
run(entry.target);
io.unobserve(entry.target);
}
});
},
{ threshold: 0.6 }
);
nums.forEach(function (el) {
io.observe(el);
});
})();
})();