Fix 4.3 and 4.4 release pages (#1090)

- Remove gsap
- Add anime.js (MIT licensed)
This commit is contained in:
Adam Scott
2025-06-23 15:09:48 -04:00
committed by GitHub
parent 7ab5e13520
commit 0d5d5474a8
7 changed files with 7812 additions and 151 deletions

View File

@@ -121,3 +121,6 @@
} }
}); });
</script> </script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,42 +1,51 @@
// GSAP for animations. import {
import { gsap } from "../modules/gsap@3.12.5.min.mjs" animate,
import { ScrollTrigger } from "../modules/gsap@3.12.5_ScrollTrigger.min.mjs" createTimeline,
import detectPlatform from "../modules/detect-browser.mjs" onScroll,
utils,
eases,
} from "../modules/anime@4.0.2_esm.min.js";
import detectPlatform from "../modules/detect-browser.mjs";
gsap.registerPlugin(ScrollTrigger); const { outCirc } = eases;
// Release numbers. // Release numbers.
const RELEASE_NUMBERS_INITIAL_DELAY_S = 1; const RELEASE_NUMBERS_INITIAL_DELAY_S = 1;
const RELEASE_NUMBERS_DURATION_S = 1; const RELEASE_NUMBERS_DURATION_S = 1;
const RELEASE_NUMBERS_EASE_NAME = "power2.out"; const RELEASE_NUMBERS_EASE_NAME = "easeOut";
const RELEASE_NUMBERS_MAX_BAR_WIDTH_PX = 200; const RELEASE_NUMBERS_MAX_BAR_WIDTH_PX = 200;
const releaseNumbersEase = gsap.parseEase(RELEASE_NUMBERS_EASE_NAME);
const numberFormat = new Intl.NumberFormat("en-US"); const numberFormat = new Intl.NumberFormat("en-US");
for (const el of ["commits", "contributors"]) { for (const el of ["commits", "contributors"]) {
const timeline = gsap.timeline(); const timeline = createTimeline();
const lines = gsap.utils.toArray(`.release-header .header-numbers-${el} .header-numbers-line`).reverse(); const lines = utils
.$(`.release-header .header-numbers-${el} .header-numbers-line`)
.reverse();
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const line = lines[i]; const line = lines[i];
const localTimeline = gsap.timeline(); const localTimeline = createTimeline();
localTimeline.to(line.querySelector(".bar"), { localTimeline.add(line.querySelector(".bar"), {
delay: i == 0 delay: i == 0 ? RELEASE_NUMBERS_INITIAL_DELAY_S * 1000 : 0,
? RELEASE_NUMBERS_INITIAL_DELAY_S duration: RELEASE_NUMBERS_DURATION_S * 1000,
: 0, ease: outCirc,
duration: RELEASE_NUMBERS_DURATION_S, width: {
ease: RELEASE_NUMBERS_EASE_NAME, to: `${(Number(line.dataset.value) / Number(line.dataset.max)) * RELEASE_NUMBERS_MAX_BAR_WIDTH_PX}px`,
width: `${(Number(line.dataset.value) / Number(line.dataset.max)) * RELEASE_NUMBERS_MAX_BAR_WIDTH_PX}px`, },
onUpdate: () => { onUpdate: () => {
line.querySelector(".number").innerText = numberFormat.format( line.querySelector(".number").innerText = numberFormat.format(
Math.round(releaseNumbersEase(localTimeline.progress()) * Number(line.dataset.value)) Math.round(
outCirc(localTimeline.progress) * Number(line.dataset.value),
),
); );
}, },
onComplete: () => { onComplete: () => {
line.querySelector(".number").innerText = numberFormat.format(Number(line.dataset.value)); line.querySelector(".number").innerText = numberFormat.format(
} Number(line.dataset.value),
);
},
}); });
timeline.add(localTimeline); timeline.sync(localTimeline);
// Set commits to 0 // Set commits to 0
line.querySelector(".number").innerText = "0"; line.querySelector(".number").innerText = "0";
@@ -46,50 +55,70 @@ for (const el of ["commits", "contributors"]) {
// Add a scrolling effect to each card and title. // Add a scrolling effect to each card and title.
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
/** @type {HTMLDivElement[]} */ /** @type {HTMLDivElement[]} */
const elements = Array.from(gsap.utils.toArray(".release-content .section .release-cards .release-card, .release-content .section .section-title")); const elements = Array.from(
utils.$(
".release-content .section .release-cards .release-card, .release-content .section .section-title",
),
);
for (const element of elements) { for (const element of elements) {
if (element.getBoundingClientRect().top < windowHeight) { if (element.getBoundingClientRect().top < windowHeight) {
continue; continue;
} }
const timeline = gsap.timeline({ const scrollObserver = onScroll({
scrollTrigger: { target: element,
trigger: element, enter: { target: "top", container: "bottom" },
start: "top bottom",
}
}); });
timeline.from(element, { animate(element, {
y: "+=50", y: {
duration: 0.5, from: "+=50px",
opacity: 0 },
duration: 500,
opacity: {
from: 0,
},
autoplay: scrollObserver,
}); });
} }
// Hide downloads that aren't for the user's platform. // Hide downloads that aren't for the user's platform.
const platformData = detectPlatform(navigator.userAgent, navigator.userAgentData); const platformData = detectPlatform(
navigator.userAgent,
navigator.userAgentData,
);
let platformName = "windows"; let platformName = "windows";
switch (platformData.os) { switch (platformData.os) {
case "mac": case "mac":
case "iphone": case "iphone":
case "ipad": { case "ipad":
platformName = "macos"; {
} break; platformName = "macos";
}
break;
case "linux": { case "linux":
platformName = "linux"; {
} break; platformName = "linux";
}
break;
case "android": { case "android":
platformName = "android"; {
} break; platformName = "android";
}
break;
case "windows": case "windows":
default: default:
break; break;
} }
const releasePlatformContainer = document.querySelector(".release-platform-container"); const releasePlatformContainer = document.querySelector(
".release-platform-container",
);
if (releasePlatformContainer != null) { if (releasePlatformContainer != null) {
const releasePlatform = releasePlatformContainer.querySelector(`.release-platform-${platformName}`); const releasePlatform = releasePlatformContainer.querySelector(
`.release-platform-${platformName}`,
);
if (releasePlatform != null) { if (releasePlatform != null) {
releasePlatform.classList.add("active"); releasePlatform.classList.add("active");
} }
@@ -102,7 +131,11 @@ if (downloadOther != null) {
} }
// Add relative weight based on author data // Add relative weight based on author data
const authors = Array.from(document.querySelectorAll("#special-thanks-release-authors .release-card-authors .release-card-author")); const authors = Array.from(
document.querySelectorAll(
"#special-thanks-release-authors .release-card-authors .release-card-author",
),
);
let max_prs = 0; let max_prs = 0;
for (const author of authors) { for (const author of authors) {
max_prs = Math.max(max_prs, Number(author.dataset.prs)); max_prs = Math.max(max_prs, Number(author.dataset.prs));
@@ -157,7 +190,12 @@ for (const cLink of cLinks) {
} }
const contributorsId = `${parentId}-contributors`; const contributorsId = `${parentId}-contributors`;
const contributorsReducer = (previousValue, currentValue, currentIndex, array) => { const contributorsReducer = (
previousValue,
currentValue,
currentIndex,
array,
) => {
if (currentIndex === 0) { if (currentIndex === 0) {
return `${previousValue} ${currentValue}`; return `${previousValue} ${currentValue}`;
} else if (currentIndex < array.length - 1) { } else if (currentIndex < array.length - 1) {
@@ -170,14 +208,19 @@ for (const cLink of cLinks) {
/** @type {String[]} */ /** @type {String[]} */
const contributors = cLink.dataset.contributors.split(","); const contributors = cLink.dataset.contributors.split(",");
const contributorsText = contributors.reduce(contributorsReducer, "Contributed by"); const contributorsText = contributors.reduce(
const contributorsHtml = contributors.map((val) => { contributorsReducer,
const link = document.createElement("a"); "Contributed by",
link.href = `https://github.com/${val}`; );
link.target = "_blank"; const contributorsHtml = contributors
link.textContent = val; .map((val) => {
return link.outerHTML; const link = document.createElement("a");
}).reduce(contributorsReducer, "Contributed by"); link.href = `https://github.com/${val}`;
link.target = "_blank";
link.textContent = val;
return link.outerHTML;
})
.reduce(contributorsReducer, "Contributed by");
const button = cLink.appendChild(document.createElement("button")); const button = cLink.appendChild(document.createElement("button"));
button.classList.add("c-link-popover-button"); button.classList.add("c-link-popover-button");
@@ -211,15 +254,18 @@ function computePosition(invoker, popover) {
const popoverRect = popover.getBoundingClientRect(); const popoverRect = popover.getBoundingClientRect();
const windowSize = { const windowSize = {
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight height: window.innerHeight,
}; };
const padding = 10; const padding = 10;
const popoverPosition = { const popoverPosition = {
x: invokerRect.x - (popoverRect.width / 2), x: invokerRect.x - popoverRect.width / 2,
y: invokerRect.y - popoverRect.height - padding, y: invokerRect.y - popoverRect.height - padding,
}; };
popoverPosition.x = Math.min(Math.max(popoverPosition.x, 0), windowSize.width - popoverRect.width); popoverPosition.x = Math.min(
Math.max(popoverPosition.x, 0),
windowSize.width - popoverRect.width,
);
if (popoverPosition.y < 0) { if (popoverPosition.y < 0) {
popoverPosition.y = invokerRect.y + invokerRect.height + padding; popoverPosition.y = invokerRect.y + invokerRect.height + padding;
} }
@@ -235,7 +281,9 @@ function positionPopover(event) {
return; return;
} }
const popover = event.target; const popover = event.target;
const invoker = document.querySelector(`[popovertarget="${popover.getAttribute("id")}"`); const invoker = document.querySelector(
`[popovertarget="${popover.getAttribute("id")}"`,
);
const { x, y } = computePosition(invoker, popover); const { x, y } = computePosition(invoker, popover);
Object.assign(popover.style, { Object.assign(popover.style, {
left: `${x}px`, left: `${x}px`,
@@ -271,7 +319,10 @@ const lazyVideoObserver = new IntersectionObserver((entries, observer) => {
} }
for (var entryChildElement of entry.target.children) { for (var entryChildElement of entry.target.children) {
if (typeof entryChildElement.tagName === "string" && entryChildElement.tagName === "SOURCE") { if (
typeof entryChildElement.tagName === "string" &&
entryChildElement.tagName === "SOURCE"
) {
entryChildElement.src = entryChildElement.dataset.src; entryChildElement.src = entryChildElement.dataset.src;
} }
} }
@@ -296,12 +347,14 @@ const showScrollToTop = () => {
} }
scrollState = "show"; scrollState = "show";
if (scrollToTopTween != null) { if (scrollToTopTween != null) {
scrollToTopTween.kill(); scrollToTopTween.cancel();
} }
scrollToTopElement.style.display = "block"; scrollToTopElement.style.display = "block";
scrollToTopTween = gsap.to(scrollToTopElement, { scrollToTopTween = animate(scrollToTopElement, {
opacity: 1, opacity: {
duration: 0.5, to: 1,
},
duration: 500,
}); });
}; };
const hideScrollToTop = () => { const hideScrollToTop = () => {
@@ -310,14 +363,16 @@ const hideScrollToTop = () => {
} }
scrollState = "hide"; scrollState = "hide";
if (scrollToTopTween != null) { if (scrollToTopTween != null) {
scrollToTopTween.kill(); scrollToTopTween.cancel();
} }
scrollToTopTween = gsap.to(scrollToTopElement, { scrollToTopTween = animate(scrollToTopElement, {
opacity: 0, opacity: {
duration: 0.5, to: 0,
},
duration: 500,
onComplete: () => { onComplete: () => {
scrollToTopElement.style.display = "none"; scrollToTopElement.style.display = "none";
} },
}); });
}; };
const scrollToTopObserver = new IntersectionObserver((entries, observer) => { const scrollToTopObserver = new IntersectionObserver((entries, observer) => {
@@ -327,7 +382,6 @@ const scrollToTopObserver = new IntersectionObserver((entries, observer) => {
hideScrollToTop(); hideScrollToTop();
} else { } else {
const rect = linksElement.getBoundingClientRect(); const rect = linksElement.getBoundingClientRect();
console.log(rect);
if (rect.y > window.innerHeight) { if (rect.y > window.innerHeight) {
hideScrollToTop(); hideScrollToTop();
} else { } else {

View File

@@ -1,34 +1,35 @@
// GSAP for animations. import {
import { gsap } from "../modules/gsap@3.12.5.min.mjs"; animate,
import { ScrollTrigger } from "../modules/gsap@3.12.5_ScrollTrigger.min.mjs"; createTimeline,
onScroll,
eases,
} from "../modules/anime@4.0.2_esm.min.js";
import detectPlatform from "../modules/detect-browser.mjs"; import detectPlatform from "../modules/detect-browser.mjs";
gsap.registerPlugin(ScrollTrigger); const { outCirc, inCirc } = eases;
// Parallax scrolling. // Parallax scrolling.
const releaseHeaderBackground = document.querySelector( const releaseHeaderBackground = document.querySelector(
".release-header-background", ".release-header-background",
); );
gsap.to(releaseHeaderBackground, { const scrollObserver = onScroll({
scrollTrigger: { target: ".release-header",
trigger: ".release-header", enter: "top 0%-=64px",
start: "top 0%+=64px", leave: "top 100%",
end: "bottom 0%", onUpdate: () => {
onUpdate: (self) => { const progress = scrollObserver.progress;
const progress = self.progress; releaseHeaderBackground.style.transform = `
releaseHeaderBackground.style.transform = ` translateY(${progress * releaseHeaderBackground.getBoundingClientRect().height}px)
translateY(${progress * releaseHeaderBackground.getBoundingClientRect().height}px) translateZ(-1px)
translateZ(-1px) scale(2)
scale(2) `;
`; releaseHeaderBackground.style.filter = `blur(${inCirc(progress) * 5}px)`;
releaseHeaderBackground.style.filter = `blur(${easeInCirc(progress) * 5}px)`;
},
}, },
}); });
// https://easings.net/#easeInCirc const releaseHeaderBackgroundTween = animate(releaseHeaderBackground, {
function easeInCirc(x) { autoplay: scrollObserver,
return 1 - Math.sqrt(1 - Math.pow(x, 2)); ease: outCirc,
} });
// Add a scrolling effect to each card and title. // Add a scrolling effect to each card and title.
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
@@ -84,22 +85,29 @@ for (const element of elements) {
continue; continue;
} }
const timeline = gsap.timeline({ const scrollObserver = onScroll({
scrollTrigger: { trigger: element.element,
trigger: element.element, enter: {
start: "top bottom", target: "top",
container: "bottom",
}, },
});
animate(element.element, {
y: {
from: "+=50px",
},
opacity: {
from: 0,
},
duration: 500,
autoplay: scrollObserver,
ease: outCirc,
onComplete: () => { onComplete: () => {
if (element.isLastOfType) { if (element.isLastOfType) {
element.container.classList.remove("overflow-y-hidden"); element.container.classList.remove("overflow-y-hidden");
} }
}, },
}); });
timeline.from(element.element, {
y: "+=50",
duration: 0.5,
opacity: 0,
});
} }
// Hide downloads that aren't for the user's platform. // Hide downloads that aren't for the user's platform.
@@ -259,12 +267,14 @@ const showScrollToTop = () => {
} }
scrollState = "show"; scrollState = "show";
if (scrollToTopTween != null) { if (scrollToTopTween != null) {
scrollToTopTween.kill(); scrollToTopTween.cancel();
} }
scrollToTopElement.style.display = "block"; scrollToTopElement.style.display = "block";
scrollToTopTween = gsap.to(scrollToTopElement, { scrollToTopTween = animate(scrollToTopElement, {
opacity: 1, opacity: {
duration: 0.5, to: 1,
},
duration: 500,
}); });
}; };
const hideScrollToTop = () => { const hideScrollToTop = () => {
@@ -273,11 +283,13 @@ const hideScrollToTop = () => {
} }
scrollState = "hide"; scrollState = "hide";
if (scrollToTopTween != null) { if (scrollToTopTween != null) {
scrollToTopTween.kill(); scrollToTopTween.cancel();
} }
scrollToTopTween = gsap.to(scrollToTopElement, { scrollToTopTween = animate(scrollToTopElement, {
opacity: 0, opacity: {
duration: 0.5, to: 0,
},
duration: 500,
onComplete: () => { onComplete: () => {
scrollToTopElement.style.display = "none"; scrollToTopElement.style.display = "none";
}, },