update line (#1297)
This commit is contained in:
+37
-30
@@ -174,6 +174,8 @@
|
|||||||
.timeline-node {
|
.timeline-node {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(28px);
|
transform: translateY(28px);
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.2, 0.9, 0.25, 1);
|
transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.2, 0.9, 0.25, 1);
|
||||||
}
|
}
|
||||||
.timeline-node.is-visible {
|
.timeline-node.is-visible {
|
||||||
@@ -196,8 +198,8 @@
|
|||||||
<p class="text-muted text-sm font-semibold tracking-[0.25em] uppercase mb-4">Our Story</p>
|
<p class="text-muted text-sm font-semibold tracking-[0.25em] uppercase mb-4">Our Story</p>
|
||||||
<h1 class="text-4xl lg:text-6xl font-extrabold mb-5 gradient-text">The Timeline</h1>
|
<h1 class="text-4xl lg:text-6xl font-extrabold mb-5 gradient-text">The Timeline</h1>
|
||||||
<p class="text-lg text-white/70 max-w-2xl mx-auto">
|
<p class="text-lg text-white/70 max-w-2xl mx-auto">
|
||||||
How <%= botName %> grew from a late-night Discord experiment into a
|
Our history, the milestones we passed along the way, and the giants whose
|
||||||
dedicated companion for War Thunder Squadron Battles.
|
shoulders helped us climb higher.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -428,8 +430,8 @@
|
|||||||
|
|
||||||
var nodes = Array.prototype.slice.call(timeline.querySelectorAll('.timeline-node'));
|
var nodes = Array.prototype.slice.call(timeline.querySelectorAll('.timeline-node'));
|
||||||
var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||||
var drawProgress = 0; // 0 → 1, how much of the line is drawn
|
var drawProgress = 0; // 0 to 1, how much of the line is drawn
|
||||||
var animating = false;
|
var ticking = false;
|
||||||
|
|
||||||
// Build a rounded-corner path that threads through a list of points.
|
// Build a rounded-corner path that threads through a list of points.
|
||||||
function roundedPath(pts, radius) {
|
function roundedPath(pts, radius) {
|
||||||
@@ -524,30 +526,33 @@
|
|||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
function animateDraw() {
|
function clamp(value, min, max) {
|
||||||
if (animating) return;
|
return Math.max(min, Math.min(max, value));
|
||||||
animating = true;
|
}
|
||||||
var start = null;
|
|
||||||
var duration = 7200; // ms for the line to travel the whole serpentine
|
function updateFromScroll() {
|
||||||
function step(ts) {
|
ticking = false;
|
||||||
if (start === null) start = ts;
|
|
||||||
var p = Math.min((ts - start) / duration, 1);
|
|
||||||
// ease-in-out
|
|
||||||
drawProgress = p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
|
|
||||||
var len = progress.getTotalLength();
|
var len = progress.getTotalLength();
|
||||||
|
var rect = timeline.getBoundingClientRect();
|
||||||
|
var viewport = window.innerHeight || document.documentElement.clientHeight;
|
||||||
|
var start = viewport * 0.35;
|
||||||
|
var end = -rect.height + viewport * 0.45;
|
||||||
|
var raw = (start - rect.top) / (start - end);
|
||||||
|
|
||||||
|
drawProgress = clamp(raw, 0, 1);
|
||||||
progress.style.strokeDashoffset = len * (1 - drawProgress);
|
progress.style.strokeDashoffset = len * (1 - drawProgress);
|
||||||
updateComet(len);
|
updateComet(len);
|
||||||
revealNodes();
|
revealNodes();
|
||||||
if (p < 1) {
|
if (drawProgress >= 1) {
|
||||||
requestAnimationFrame(step);
|
|
||||||
} else {
|
|
||||||
drawProgress = 1;
|
|
||||||
progress.style.strokeDashoffset = 0;
|
|
||||||
comet.style.opacity = 0;
|
comet.style.opacity = 0;
|
||||||
nodes.forEach(function (n) { n.classList.add('is-visible'); });
|
nodes.forEach(function (n) { n.classList.add('is-visible'); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestAnimationFrame(step);
|
|
||||||
|
function requestScrollUpdate() {
|
||||||
|
if (ticking) return;
|
||||||
|
ticking = true;
|
||||||
|
requestAnimationFrame(updateFromScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@@ -558,21 +563,19 @@
|
|||||||
nodes.forEach(function (n) { n.classList.add('is-visible'); });
|
nodes.forEach(function (n) { n.classList.add('is-visible'); });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Start drawing only after the user has scrolled into the timeline.
|
updateFromScroll();
|
||||||
var trigger = nodes[0] || timeline;
|
window.addEventListener('scroll', requestScrollUpdate, { passive: true });
|
||||||
var io = new IntersectionObserver(function (entries) {
|
|
||||||
entries.forEach(function (e) {
|
|
||||||
if (e.isIntersecting) { animateDraw(); io.disconnect(); }
|
|
||||||
});
|
|
||||||
}, { threshold: 0.65, rootMargin: '0px 0px -16% 0px' });
|
|
||||||
io.observe(trigger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recompute geometry on resize (layout flips between 1 and 3 columns).
|
// Recompute geometry on resize (layout flips between 1 and 3 columns).
|
||||||
var resizeTimer;
|
var resizeTimer;
|
||||||
window.addEventListener('resize', function () {
|
window.addEventListener('resize', function () {
|
||||||
clearTimeout(resizeTimer);
|
clearTimeout(resizeTimer);
|
||||||
resizeTimer = setTimeout(function () { _samples = null; build(); }, 120);
|
resizeTimer = setTimeout(function () {
|
||||||
|
_samples = null;
|
||||||
|
build();
|
||||||
|
if (!reduceMotion) updateFromScroll();
|
||||||
|
}, 120);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
@@ -581,7 +584,11 @@
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
// Re-measure after fonts/icons settle so markers are positioned correctly.
|
// Re-measure after fonts/icons settle so markers are positioned correctly.
|
||||||
window.addEventListener('load', function () { _samples = null; build(); });
|
window.addEventListener('load', function () {
|
||||||
|
_samples = null;
|
||||||
|
build();
|
||||||
|
if (!reduceMotion) updateFromScroll();
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user