Add pregnancy timeline motion: growing slider fill, size pop, week-button wave
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LSDgjk1Agjy9Z2UH2n8bc3
This commit is contained in:
2 files changed
+70
-1
No files matched your search
+2
-1
@@ -266,7 +266,7 @@ button{font-family:inherit;}
|
|||||||
text-transform:uppercase;letter-spacing:0.05em;margin-bottom:8px;font-weight:600;}
|
text-transform:uppercase;letter-spacing:0.05em;margin-bottom:8px;font-weight:600;}
|
||||||
input[type="range"].week-slider{
|
input[type="range"].week-slider{
|
||||||
width:100%;-webkit-appearance:none;appearance:none;height:8px;border-radius:999px;
|
width:100%;-webkit-appearance:none;appearance:none;height:8px;border-radius:999px;
|
||||||
background:linear-gradient(to right, var(--pregnancy-soft) 0%, var(--pregnancy-soft) 100%);
|
background:linear-gradient(to right, var(--pregnancy) 0, var(--pregnancy) calc(11px + (100% - 22px) * var(--f,0)), var(--pregnancy-soft) calc(11px + (100% - 22px) * var(--f,0)), var(--pregnancy-soft) 100%);
|
||||||
outline:none;cursor:pointer;
|
outline:none;cursor:pointer;
|
||||||
}
|
}
|
||||||
input[type="range"].week-slider::-webkit-slider-thumb{
|
input[type="range"].week-slider::-webkit-slider-thumb{
|
||||||
@@ -1074,3 +1074,4 @@ footer.note{
|
|||||||
<script src="vendor/three.min.js"></script>
|
<script src="vendor/three.min.js"></script>
|
||||||
<script src="ring3d.js"></script>
|
<script src="ring3d.js"></script>
|
||||||
<script src="animations.js"></script>
|
<script src="animations.js"></script>
|
||||||
|
<script src="timeline.js"></script>
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
/* CycleWise AU - pregnancy timeline motion (Step 3).
|
||||||
|
- The week slider's track fills with colour up to the current week.
|
||||||
|
It grows the first time you scroll to it, then follows every week change.
|
||||||
|
- The baby-size picture pops a little when the week changes.
|
||||||
|
- The 40 week buttons wave in the first time they appear.
|
||||||
|
Cosmetic only: without GSAP the slider simply shows its normal look. */
|
||||||
|
(function(){
|
||||||
|
"use strict";
|
||||||
|
var slider = document.getElementById("week-slider");
|
||||||
|
var badge = document.getElementById("wk-badge");
|
||||||
|
if (!slider || !badge) return;
|
||||||
|
|
||||||
|
var hasGsap = !!window.gsap;
|
||||||
|
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
|
var animate = hasGsap && !reduce;
|
||||||
|
|
||||||
|
var fill = { f: 0 };
|
||||||
|
var target = 0;
|
||||||
|
var introDone = false;
|
||||||
|
|
||||||
|
function paint(){ slider.style.setProperty("--f", fill.f.toFixed(4)); }
|
||||||
|
function currentWeek(){
|
||||||
|
var n = parseInt((badge.textContent || "").replace(/\D/g, ""), 10);
|
||||||
|
return isNaN(n) ? (parseInt(slider.value, 10) || 1) : Math.max(1, Math.min(40, n));
|
||||||
|
}
|
||||||
|
function goTo(f){
|
||||||
|
target = f;
|
||||||
|
if (!introDone) return; // wait until the slider is on screen
|
||||||
|
if (!animate) { fill.f = f; paint(); return; }
|
||||||
|
gsap.to(fill, { f: f, duration: 0.6, ease: "power2.out", overwrite: true, onUpdate: paint });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follow every week change, whether from the slider, a week button or the calendar.
|
||||||
|
var lastWeek = currentWeek();
|
||||||
|
target = (lastWeek - 1) / 39;
|
||||||
|
new MutationObserver(function(){
|
||||||
|
var w = currentWeek();
|
||||||
|
if (w === lastWeek) return;
|
||||||
|
lastWeek = w;
|
||||||
|
goTo((w - 1) / 39);
|
||||||
|
var blob = document.querySelector("#wk-blob svg");
|
||||||
|
if (animate && blob) {
|
||||||
|
gsap.fromTo(blob, { scale: 0.8, transformOrigin: "50% 50%" },
|
||||||
|
{ scale: 1, duration: 0.5, ease: "back.out(2)", clearProps: "transform" });
|
||||||
|
}
|
||||||
|
}).observe(badge, { childList: true, characterData: true, subtree: true });
|
||||||
|
|
||||||
|
// First time the slider is visible: grow the fill from empty up to this week.
|
||||||
|
new IntersectionObserver(function(entries, obs){
|
||||||
|
if (!entries[0].isIntersecting) return;
|
||||||
|
obs.disconnect();
|
||||||
|
introDone = true;
|
||||||
|
if (!animate) { fill.f = target; paint(); return; }
|
||||||
|
gsap.to(fill, { f: target, duration: 1.2, ease: "power2.out", onUpdate: paint });
|
||||||
|
}).observe(slider);
|
||||||
|
|
||||||
|
// First time the week buttons are visible: wave them in.
|
||||||
|
var strip = document.getElementById("week-filmstrip");
|
||||||
|
if (strip && animate) {
|
||||||
|
new IntersectionObserver(function(entries, obs){
|
||||||
|
if (!entries[0].isIntersecting) return;
|
||||||
|
obs.disconnect();
|
||||||
|
gsap.from(strip.querySelectorAll(".film-item"), {
|
||||||
|
opacity: 0, scale: 0.8, duration: 0.4, stagger: 0.02, ease: "power2.out", clearProps: "all"
|
||||||
|
});
|
||||||
|
}).observe(strip);
|
||||||
|
}
|
||||||
|
})();
|
||||||
Reference in new issue
Block a user