Create project website with near-complete home page

This commit is contained in:
Keavon Chambers
2022-02-17 02:44:02 -08:00
parent 4757e8b8cd
commit 3f79df7314
13 changed files with 1555 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
<svg width="582" height="508.999" viewBox="0 0 582 508.999" xmlns="http://www.w3.org/2000/svg">
<path d="M582.5,433.615a17.985,17.985,0,0,1-1.5,8q-1.5,3-4.5,8-25.008,29.016-55,44.5-30,15.516-69,15.5-30,0-49-15.5t-29.5-39.5a292,292,0,0,1-16.5-49h-1q-39,49.008-84.5,76-45.516,27-110.5,27-80.016,0-120.5-48.5Q.5,411.623.5,335.615a366.087,366.087,0,0,1,20.5-121,343.774,343.774,0,0,1,59-106,294.033,294.033,0,0,1,92-75q53.484-27.984,119.5-28,60.984,0,91,36,30,36,40,92,10.992-33,21-66,9.984-33,20-67l96,27a746.057,746.057,0,0,1-39,99q-11.016,24-23,47.5-12,23.508-24,46.5-10.008,19.008-20,37a242.935,242.935,0,0,0-17,38q-3,7.01-3,18,0,9,4,32.5,3.984,23.508,10.5,50.5,6.492,27,16,46,9.492,19.008,19.5,19,15.984,0,29.5-11a329.717,329.717,0,0,0,25-22.5q11.484-11.484,22.5-11.5,6,0,14,5.5T582.5,433.615Zm-238-179q0-19.991-1-40.5a370.084,370.084,0,0,0-4-39.5q-2.016-12.984-4.5-35.5-2.508-22.5-7.5-46-5.016-23.484-16-39.5-11.016-15.984-29-16a55.475,55.475,0,0,0-23,4.5,119.544,119.544,0,0,0-21,12.5q-42,31.008-69.5,79.5a391.8,391.8,0,0,0-40.5,103,458.01,458.01,0,0,0-13,106.5q0,14.018,4,34a225.831,225.831,0,0,0,12,40q7.992,20.016,21,33a42.284,42.284,0,0,0,31,13q21,0,46-17.5,24.984-17.484,48.5-44a378.436,378.436,0,0,0,40-53.5q16.5-27,21.5-46a150.883,150.883,0,0,0,4-24Q344.484,266.615,344.5,254.615Z" transform="translate(-0.5 -0.616)" fill="#473a3a" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M13,17.1A3.719,3.719,0,0,0,9,14c-1.7.1-3.1,1.5-4,4.2a7.571,7.571,0,0,1-3.6,4c2.9,1,5.9,1.3,8.6.1A5.223,5.223,0,0,0,13,17.1Z" fill="#803847" />
<path d="M22.5,1.1C21.6.3,18,3.8,14.1,8.2a34.223,34.223,0,0,0-3.6,4.6,3.9,3.9,0,0,1,1.9.8,3.887,3.887,0,0,1,1.4,1.9A29.655,29.655,0,0,0,17.5,11C20.9,6,23.5,1.9,22.5,1.1Z" fill="#473a3a" />
</svg>

After

Width:  |  Height:  |  Size: 434 B

View File

@@ -0,0 +1,24 @@
<svg width="280" height="174.379" viewBox="0 0 280 174.379" xmlns="http://www.w3.org/2000/svg">
<path d="M97.072,3.951c28.8,0,54.63,3.968,71.968,10.208V51.748C151.7,58,125.869,61.956,97.072,61.956c-25.158,0-47.9-3.013-65.019-7.952v.033a80.957,80.957,0,0,1-17.815-7.87A134.476,134.476,0,0,0,21.022,59.8c4.956,7.689,6.734,14.423,6.5,14.769-.148.214-1.844-1.992-4.347-5.582-5.8-7-16.811-20.367-19.017-23.775C1.676,41.326,3.091,39.5,3.091,39.5l1.745-3.145a10.642,10.642,0,0,1-.807-3.935c0-8.463,10.9-16.119,28.023-21.635V11.9C49.176,6.981,71.914,3.951,97.072,3.951" transform="translate(66.67 61.101)" fill="#a52b00" />
<path d="M23.341,29.761s1.218,1.844-.955,5.812c-1.91,3.507-11.509,17.288-16.6,24.516-2.173,3.688-3.639,5.96-3.754,5.746-.214-.346,1.367-7.212,5.68-15.115,2.634-5.516,5.944-13.369,6.9-17.255A50.462,50.462,0,0,1,1.1,41.369V4.537c12.1,5.1,19.33,11.492,19.33,18.424,0,.231-.016.461-.033.692Z" transform="translate(238.251 70.164)" fill="#a52b00" />
<path d="M230.065,99.892s2.914,1.515,0,6.932c-2.569,4.791-16.547,24.467-23.956,34.79-3.013,5.1-5.1,8.3-5.417,8.117-.494-.3.362-8.693,6.141-19.461,4.248-9.467,9.418-23.792,7.426-24.944,0,0-5.8-5.121-15.362-3.408-83.756,40.948-174.049-.708-174.049-.708-.181-.115.132.132,0,0a17.936,17.936,0,0,0-6.4,4.66c-1.893,1.6,6.108,15.526,12.25,24.582,8.018,10.093,10.406,18.688,9.961,19.083-.3.263-3.062-2.667-7.129-7.393-9.6-9.319-27.809-27.085-31.332-31.563-4.017-5.088-1.284-7.244-1.284-7.244L18.921,84.2l.165-.494-6.372-9.22a3.462,3.462,0,0,1-.362-3.227,3.218,3.218,0,0,1,2.42-2.009l10.784-1.828Q26.2,66.139,26.84,64.9L22.329,54.548a3.437,3.437,0,0,1,.247-3.244,3.207,3.207,0,0,1,2.783-1.482l10.916.4c.543-.741,1.136-1.465,1.712-2.173L35.5,36.93a3.4,3.4,0,0,1,.84-3.112,3.114,3.114,0,0,1,3-.889L49.99,35.547c.692-.609,1.383-1.218,2.091-1.811L51.7,22.343a3.338,3.338,0,0,1,1.416-2.881A3.1,3.1,0,0,1,56.23,19.2l9.912,4.709c.807-.461,1.6-.906,2.4-1.35l1.778-11.229a3.268,3.268,0,0,1,1.91-2.536,3.1,3.1,0,0,1,3.112.362L84.2,15.806c.873-.3,1.745-.576,2.634-.84l3.8-10.636a3.225,3.225,0,0,1,2.371-2.107,3.145,3.145,0,0,1,2.98.988l7.442,8.331c.906-.1,1.811-.2,2.717-.263l5.746-9.7a3.125,3.125,0,0,1,5.433,0l5.763,9.7c.906.066,1.811.165,2.7.263l7.459-8.331a3.1,3.1,0,0,1,2.947-.988,3.248,3.248,0,0,1,2.387,2.107l3.787,10.636c.906.263,1.778.543,2.651.84l8.858-6.652a3.083,3.083,0,0,1,3.1-.362,3.287,3.287,0,0,1,1.926,2.536l1.762,11.229c.807.445,1.614.906,2.4,1.35l9.945-4.709a3.076,3.076,0,0,1,3.1.263,3.338,3.338,0,0,1,1.416,2.881l-.379,11.394c.708.593,1.416,1.2,2.091,1.811l10.653-2.618a3.114,3.114,0,0,1,3,.889,3.4,3.4,0,0,1,.84,3.112l-2.5,11.114q.864,1.062,1.729,2.173l10.916-.4a3.171,3.171,0,0,1,2.783,1.482,3.484,3.484,0,0,1,.247,3.244L202.371,64.9c.445.823.873,1.663,1.3,2.519l10.752,1.828a3.213,3.213,0,0,1,2.453,2.009,3.509,3.509,0,0,1-.362,3.227l-6.372,9.22c.2.642.379,1.268.56,1.91Z" transform="translate(48.634)" fill="#f74c00" />
<path d="M49.664,25.512V18.976C47.606,16.144,28.293-9.525,4.172,22.3l29.554,2.733s-.181.181-.527.477Z" transform="translate(161.645 100.773)" />
<path d="M64.464,79.271C31.254,61.851,30,47.428,30,47.428-6.928,20.557,24.635,5.377,24.635,5.377c-.461,17.14,9.7,26.936,9.7,26.936l.922-30.822C69.5,25.678,40.886,48.432,40.886,48.432c4.116,10.225,28.5,19.725,28.5,19.725Z" transform="translate(11.851 23.058)" fill="#f74c00" />
<path d="M8.2,8.873c-7.738,12.513,0,19.758,0,19.758,6.438,9.22,18.045,0,18.045,0,7.1-6.586,0-19.758,0-19.758-9.023-9.879-18.045,0-18.045,0" transform="translate(172.169 69.318)" />
<path d="M15.542,11.513c0-3.853-2.272-6.965-5.071-6.965-2.783,0-5.055,3.112-5.055,6.965s2.272,6.965,5.055,6.965c2.8,0,5.071-3.112,5.071-6.965" transform="translate(175.285 70.334)" fill="#fff" />
<path d="M12.449,6.021c-14.868,23.067,7,27.282,7,27.282,17.123-1,12.711-18.836,12.711-18.836C27.926-.828,12.449,6.021,12.449,6.021" transform="translate(127.65 69.47)" />
<path d="M18.464,11.73c0-3.968-2.338-7.179-5.219-7.179S8.025,7.762,8.025,11.73s2.338,7.179,5.219,7.179,5.219-3.211,5.219-7.179" transform="translate(129.406 70.38)" fill="#fff" />
<path d="M83.579,5.767c-2.5,25.553-33.341,37.474-33.341,37.474C21.079,76.45,1.914,53.465,1.914,53.465A36.086,36.086,0,0,0,31.847,38.729C10.262,33.016,2.21,37.709,2.21,37.709,28.044.235,46.27,33.494,46.27,33.494l5.647-1.317C72.021,18.642,75.248,5.767,75.248,5.767Z" transform="translate(164.907 89.185)" fill="#f74c00" />
<path d="M0,0H221.315V11.047L97.653,20.453,0,11.047Z" transform="matrix(-0.827, -0.562, 0.562, -0.827, 204.507, 161.529)" fill="#6e96ba" />
<rect width="221.315" height="11.047" transform="matrix(-0.827, -0.562, 0.562, -0.827, 210.718, 152.388)" fill="#89a9cc" />
<path d="M40.819,31.236,8.449,9.256,2.242,18.394Z" transform="translate(202.264 143.142)" fill="#ccc593" />
<path d="M34.612,39.835,2.242,17.854,8.449,8.7Z" transform="translate(208.471 134.543)" fill="#e2ddaf" />
<path d="M19.415,23.612,7.774,9.749,5.008,13.832,2.242,17.9Z" transform="translate(223.668 150.766)" fill="#2b2b2b" />
<rect width="8.782" height="11.047" transform="translate(27.641 28.034) rotate(-145.774)" fill="#d8d8d8" />
<path d="M20.163.743,36.151,11.61l-6.207,9.138L17.809,12.5a4.657,4.657,0,0,1-1.235-6.471Z" transform="translate(-15.767 11.49)" fill="#cea097" />
<path d="M25.451,1.1,37.586,9.353l-6.207,9.138L15.391,7.624,18.98,2.339A4.66,4.66,0,0,1,25.451,1.1" transform="translate(-10.995 4.609)" fill="#d8b1a7" />
<rect width="8.782" height="11.047" transform="translate(21.431 37.175) rotate(-145.774)" fill="#c1c1c1" />
<path d="M47.439,45.875,31.551,38.729C9.965,33.016,1.914,37.709,1.914,37.709,27.747.235,45.99,33.494,45.99,33.494l5.631-1.317C71.725,18.642,74.968,5.767,74.968,5.767H83.3C80.8,31.32,49.958,43.241,49.958,43.241c-.856.971-1.679,1.745-2.519,2.634" transform="translate(165.187 89.185)" fill="#f74c00" />
<path d="M24.634,1.727c-.445,17.14,9.7,26.936,9.7,26.936L46.483,38.773a34.625,34.625,0,0,1-5.6,6.01C45.018,55.007,69.4,64.507,69.4,64.507L64.463,75.621C31.253,58.2,30,43.778,30,43.778-6.929,16.908,24.634,1.727,24.634,1.727" transform="translate(11.852 26.708)" fill="#f74c00" />
<rect width="280" height="174.378" fill="none" />
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="231.228" height="240.004" viewBox="0 0 231.228 240.004">
<g id="Logo_Icon" data-name="Logo Icon" transform="translate(0.007 0.004)">
<rect id="Rectangle_52" data-name="Rectangle 52" width="231.221" height="240" transform="translate(0 0)" fill="none"/>
<path id="Path_54" data-name="Path 54" d="M149.474,6.026a10.475,10.475,0,0,0-8.169-4.72H54.2a10.475,10.475,0,0,0-8.169,4.72L2.477,81.459a10.5,10.5,0,0,0,0,9.429l43.556,75.444a10.465,10.465,0,0,0,8.169,4.71h87.1a10.465,10.465,0,0,0,8.169-4.71l43.556-75.444a10.5,10.5,0,0,0,0-9.429Z" transform="translate(12.232 11.749)" fill="#f1decd"/>
<path id="Path_55" data-name="Path 55" d="M73.237,112.684l57.085-32.417L98.2,24.622,84.546.974H8.453Z" transform="translate(76.068 8.76)" fill="#3ea8ff"/>
<path id="Path_56" data-name="Path 56" d="M84.836,50.93,56,.974H16.922L4.873,17.693,39.26,77.248l30.847,53.436,45.926-25.718Z" transform="translate(43.849 8.762)" fill="#2180ce"/>
<path id="Path_57" data-name="Path 57" d="M69.21,9.294,15.494,35.512,81.788,136.334Z" transform="translate(139.433 83.636)" fill="#deba92"/>
<path id="Path_58" data-name="Path 58" d="M57.141,11.606,11.565,37.924l93.582,56.815Z" transform="translate(104.078 104.438)" fill="#d49b64"/>
<path id="Path_59" data-name="Path 59" d="M72.991,159.707l-35-60.615a5,5,0,1,1,8.649-5l35,60.615a5,5,0,1,1-8.649,5m158.187,59.275a9.955,9.955,0,0,1-3.05,8.149c-4.19,5.07-22.408,8.879-36.147,10.769A216.3,216.3,0,0,1,164.5,240c-8.629-.09-20.628-2.26-32.037-2.97-16.109-.99-69.444-2.96-87.763-2.9-20.578.08-24.708-1.1-28.2-4.08-1.36-1.15,10.319-7.019,35.027-9.029,60.215-4.91,113.311-5.5,131.419-4.63a86.235,86.235,0,0,1,21.468,3.83l-38.587-27.678a19.952,19.952,0,0,1-10.849,3.32H64.991a20.009,20.009,0,0,1-17.319-10l-45-77.933a20.011,20.011,0,0,1,0-20L47.673,10A20.009,20.009,0,0,1,64.991,0h89.992a20.013,20.013,0,0,1,17.329,10l33.187,57.5,11.8,20.438-.04.02.02.01.03-.03.06.15a2.722,2.722,0,0,1,.11.25,19.993,19.993,0,0,1,2.45,8.089c.03.48,10.319,112.471,11.179,121.86ZM60.772,27.308,116.9,124.54A87.866,87.866,0,0,1,138.305,122l14.769-20.078,24.768-2.75a87.882,87.882,0,0,1,12.889-17.259L157.474,24.3a9.621,9.621,0,0,0-7.489-4.31H69.991a9.618,9.618,0,0,0-7.5,4.33Zm81.813,148.558-30.927-22.178a9.831,9.831,0,0,1-2.79-3.15l-.04.02L49.223,47.316,22.495,93.6a9.636,9.636,0,0,0,0,8.659l40,69.274a9.618,9.618,0,0,0,7.5,4.33Zm63.8-4.26-7.029-70.9a91.359,91.359,0,0,0-11.519,15.789l-24.768,2.75L148.3,139.318a91.516,91.516,0,0,0-19.448,2.09l57.9,41.527a19.214,19.214,0,0,1,19.638-11.329" transform="translate(-0.007 -0.004)" fill="#473a3a"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,157 @@
let carouselImages;
let carouselDirectionPrev;
let carouselDirectionNext;
let carouselDots;
let carouselDescriptions;
let carouselDragLastClientX;
let velocityDeltaWindow = Array.from({ length: 20 }, () => ({ time: 0, delta: 0 }));
window.addEventListener("DOMContentLoaded", initializeCarousel);
window.addEventListener("pointerup", dragEnd);
window.addEventListener("scroll", dragEnd);
window.addEventListener("pointermove", dragMove);
function initializeCarousel() {
carouselImages = document.querySelectorAll(".carousel img");
carouselImages.forEach((image) => {
image.addEventListener("pointerdown", dragBegin);
});
carouselDirectionPrev = document.querySelector(".carousel-controls .direction.prev");
carouselDirectionNext = document.querySelector(".carousel-controls .direction.next");
carouselDots = document.querySelectorAll(".carousel-controls .dot");
carouselDescriptions = document.querySelectorAll(".screenshot-description p");
carouselDirectionPrev.addEventListener("click", () => slideDirection("prev", false, true));
carouselDirectionNext.addEventListener("click", () => slideDirection("next", false, true));
Array.from(carouselDots).forEach((dot) => dot.addEventListener("click", (event) => {
const index = Array.from(carouselDots).indexOf(event.target);
slideTo(index, true);
}));
}
function slideDirection(direction, clamped = false, smooth) {
const directionIndexOffset = { prev: -1, next: 1 }[direction];
const offsetDotIndex = currentClosestImageIndex() + directionIndexOffset;
const nextDotIndex = (offsetDotIndex + carouselDots.length) % carouselDots.length;
const unwrappedNextDotIndex = clamp(offsetDotIndex, 0, carouselDots.length - 1);
if (clamped) slideTo(unwrappedNextDotIndex, smooth);
else slideTo(nextDotIndex, smooth);
}
function slideTo(index, smooth) {
const activeDot = document.querySelector(".carousel-controls .dot.active");
activeDot.classList.remove("active");
carouselDots[index].classList.add("active");
const activeDescription = document.querySelector(".screenshot-description p.active");
activeDescription.classList.remove("active");
carouselDescriptions[index].classList.add("active");
setCurrentTransform(index * -100, "%", smooth)
}
function currentTransform() {
const currentTransformMatrix = window.getComputedStyle(carouselImages[0]).transform;
// Grab the X value from the format that looks like: `matrix(1, 0, 0, 1, -1332.13, 0)` or `none`
return Number(currentTransformMatrix.split(",")[4] || "0");
}
function setCurrentTransform(x, unit, smooth) {
Array.from(carouselImages).forEach((image) => {
image.style.transitionTimingFunction = smooth ? "ease-in-out" : "cubic-bezier(0, 0, 0.2, 1)";
image.style.transform = `translateX(${x}${unit})`;
});
}
function currentClosestImageIndex() {
const currentTransformX = -currentTransform();
const imageWidth = carouselImages[0].getBoundingClientRect().width;
return Math.round(currentTransformX / imageWidth);
}
function currentActiveDotIndex() {
const activeDot = document.querySelector(".carousel-controls .dot.active");
return Array.from(carouselDots).indexOf(activeDot);
}
function dragBegin(event) {
event.preventDefault();
carouselDragLastClientX = event.clientX;
setCurrentTransform(currentTransform(), "px", false);
document.querySelector("#screenshots").classList.add("dragging");
}
function dragEnd() {
if (!carouselImages) return;
carouselDragLastClientX = undefined;
document.querySelector("#screenshots").classList.remove("dragging");
const onlyRecentVelocityDeltaWindow = velocityDeltaWindow.filter((delta) => delta.time > Date.now() - 1000);
const timeRange = Date.now() - onlyRecentVelocityDeltaWindow[0]?.time;
// Weighted (higher by recency) sum of velocity deltas from previous window of frames
const recentVelocity = onlyRecentVelocityDeltaWindow.reduce((acc, entry) => {
const timeSinceNow = Date.now() - entry.time;
const recencyFactorScore = 1 - (timeSinceNow / timeRange);
return acc + entry.delta * recencyFactorScore;
}, 0);
const closestImageIndex = currentClosestImageIndex();
const activeDotIndex = currentActiveDotIndex();
// If the speed is fast enough, slide to the next or previous image in that direction
if (Math.abs(recentVelocity) > 10) {
// Positive velocity should go to the previous image
if (recentVelocity > 0) {
// Don't apply the velocity-based fling if we're already snapping to the next image
if (closestImageIndex >= activeDotIndex) {
slideDirection("prev", true, false);
return;
}
}
// Negative velocity should go to the next image
else {
// Don't apply the velocity-based fling if we're already snapping to the next image
if (closestImageIndex <= activeDotIndex) {
slideDirection("next", true, false);
return;
}
}
}
// If we didn't slide in a direction due to clear velocity, just snap to the closest image
slideTo(clamp(closestImageIndex, 0, carouselDots.length - 1), true);
}
function dragMove(event) {
if (carouselDragLastClientX === undefined) return;
event.preventDefault();
const LEFT_MOUSE_BUTTON = 1;
if (!(event.buttons & LEFT_MOUSE_BUTTON)) {
dragEnd();
return;
}
const deltaX = event.clientX - carouselDragLastClientX;
velocityDeltaWindow.shift();
velocityDeltaWindow.push({ time: Date.now(), delta: deltaX });
const newTransformX = currentTransform() + deltaX;
setCurrentTransform(newTransformX, "px", false);
carouselDragLastClientX = event.clientX;
}
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}

115
website/static/js/navbar.js Normal file
View File

@@ -0,0 +1,115 @@
const NAV_BUTTON_INITIAL_FONT_SIZE = 36;
const RIPPLE_ANIMATION_MILLISECONDS = 100;
const RIPPLE_WIDTH = 150;
const HANDLE_STRETCH = 0.4;
let ripplesInitialized;
let navButtons;
let navButtonFontSize;
let rippleSvg;
let ripplePath;
let fullRippleHeight;
let ripples;
let activeRippleIndex;
window.addEventListener("DOMContentLoaded", initializeRipples);
window.addEventListener("resize", () => animate(true));
function setRipples(mediaQueryScaleFactor) {
const rippleSvgRect = rippleSvg.getBoundingClientRect();
const rippleSvgLeft = rippleSvgRect.left;
const rippleSvgWidth = rippleSvgRect.width;
let path = `M 0,${fullRippleHeight + 3} `;
ripples.forEach((ripple) => {
if (!ripple.animationStartTime || !ripple.animationEndTime) return;
const t = Math.min((Date.now() - ripple.animationStartTime) / (ripple.animationEndTime - ripple.animationStartTime), 1);
const height = fullRippleHeight * (ripple.goingUp ? ease(t) : 1 - ease(t));
const buttonRect = ripple.element.getBoundingClientRect();
const buttonCenter = buttonRect.width / 2;
const rippleCenter = RIPPLE_WIDTH / 2 * mediaQueryScaleFactor;
const rippleOffset = rippleCenter - buttonCenter;
const rippleStartX = buttonRect.left - rippleSvgLeft - rippleOffset;
const rippleRadius = RIPPLE_WIDTH / 2 * mediaQueryScaleFactor;
const handleRadius = rippleRadius * HANDLE_STRETCH;
path += `L ${rippleStartX},${fullRippleHeight + 3} `;
path += `c ${handleRadius},0 ${rippleRadius - handleRadius},-${height} ${rippleRadius},-${height} `;
path += `s ${rippleRadius - handleRadius},${height} ${rippleRadius},${height} `;
});
path += `l ${rippleSvgWidth},0`;
ripplePath.setAttribute("d", path);
}
function initializeRipples() {
ripplesInitialized = true;
navButtons = document.querySelectorAll("header nav a");
rippleSvg = document.querySelector("header .ripple");
ripplePath = rippleSvg.querySelector("path");
fullRippleHeight = Number.parseInt(window.getComputedStyle(rippleSvg).height) - 4;
ripples = Array.from(navButtons).map((button) => ({
element: button,
animationStartTime: null,
animationEndTime: null,
goingUp: false,
}));
activeRippleIndex = ripples.findIndex((ripple) => ripple.element.getAttribute("href") === window.location.pathname);
ripples.forEach((ripple) => {
const updateTimings = (goingUp) => {
const start = ripple.animationStartTime;
const now = Date.now();
const stop = ripple.animationStartTime + RIPPLE_ANIMATION_MILLISECONDS;
const elapsed = now - start;
const remaining = stop - now;
ripple.animationStartTime = now < stop ? now - remaining : now;
ripple.animationEndTime = now < stop ? now + elapsed : now + RIPPLE_ANIMATION_MILLISECONDS;
ripple.goingUp = goingUp;
animate();
};
ripple.element.addEventListener("pointerenter", () => updateTimings(true));
ripple.element.addEventListener("pointerleave", () => updateTimings(false));
});
ripples[activeRippleIndex] = {
...ripples[activeRippleIndex],
animationStartTime: Date.now(),
animationEndTime: Date.now() + RIPPLE_ANIMATION_MILLISECONDS,
goingUp: true,
};
animate();
}
function animate(forceRefresh) {
if (!ripplesInitialized) return;
navButtonFontSize = Number.parseInt(window.getComputedStyle(navButtons[0]).fontSize) || 36;
const mediaQueryScaleFactor = navButtonFontSize / NAV_BUTTON_INITIAL_FONT_SIZE;
const animateThisFrame = ripples.some((ripple) => ripple.animationStartTime && ripple.animationEndTime && Date.now() <= ripple.animationEndTime);
if (animateThisFrame || forceRefresh) {
setRipples(mediaQueryScaleFactor);
window.requestAnimationFrame(animate);
}
}
function ease(x) {
return 1 - (1 - x) * (1 - x);
}