@widelab-nc/widelab 1.1.33 → 1.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -2
- package/dist/index.js.map +3 -3
- package/package.json +2 -1
- package/src/index.js +126 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@widelab-nc/widelab",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.34",
|
|
4
4
|
"description": "Widelab starter template based on Finsweet template + add-ons.",
|
|
5
5
|
"homepage": "https://widelab.co",
|
|
6
6
|
"license": "ISC",
|
|
@@ -57,3 +57,4 @@
|
|
|
57
57
|
"gsap": "npm:@gsap/shockingly@^3.12.5"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
|
package/src/index.js
CHANGED
|
@@ -1431,6 +1431,132 @@ window.servicesSliders = function(e) {
|
|
|
1431
1431
|
});
|
|
1432
1432
|
}
|
|
1433
1433
|
|
|
1434
|
+
// Play-once timeline: children fade-in from bottom with stagger
|
|
1435
|
+
window.initBentoRevealTimeline = function (container) {
|
|
1436
|
+
// Respect reduced motion
|
|
1437
|
+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
1438
|
+
container.querySelectorAll(':scope > *').forEach(el => {
|
|
1439
|
+
el.style.opacity = 1;
|
|
1440
|
+
el.style.transform = 'none';
|
|
1441
|
+
});
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
const items = Array.from(container.children); // direct children only
|
|
1446
|
+
|
|
1447
|
+
// Set initial state
|
|
1448
|
+
gsap.set(items, { opacity: 0, y: 24 });
|
|
1449
|
+
|
|
1450
|
+
// Build timeline that plays when scrolled into view
|
|
1451
|
+
const tl = gsap.timeline({
|
|
1452
|
+
scrollTrigger: {
|
|
1453
|
+
trigger: container,
|
|
1454
|
+
start: 'top 80%', // when top of container hits 80% of viewport
|
|
1455
|
+
end: 'bottom 40%', // not critical for play-only, but nice bounds
|
|
1456
|
+
toggleActions: 'play none none none',
|
|
1457
|
+
once: true
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
tl.to(items, {
|
|
1462
|
+
opacity: 1,
|
|
1463
|
+
y: 0,
|
|
1464
|
+
duration: 0.6,
|
|
1465
|
+
ease: 'power2.out',
|
|
1466
|
+
stagger: 0.12
|
|
1467
|
+
});
|
|
1468
|
+
};
|
|
1469
|
+
|
|
1470
|
+
// Scrubbed timeline: progress tied to scroll progress
|
|
1471
|
+
window.initBentoRevealScrub = function (container) {
|
|
1472
|
+
// Respect reduced motion
|
|
1473
|
+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
1474
|
+
container.querySelectorAll(':scope > *').forEach(el => {
|
|
1475
|
+
el.style.opacity = 1;
|
|
1476
|
+
el.style.transform = 'none';
|
|
1477
|
+
});
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
const items = Array.from(container.children); // direct children only
|
|
1482
|
+
|
|
1483
|
+
// Important: define from state in timeline for scrub to interpolate smoothly
|
|
1484
|
+
const tl = gsap.timeline({
|
|
1485
|
+
scrollTrigger: {
|
|
1486
|
+
trigger: container,
|
|
1487
|
+
start: 'top 90%', // start easing in slightly later
|
|
1488
|
+
end: 'bottom 65%', // full reveal by near the end of container
|
|
1489
|
+
scrub: 0.5, // smoothing; use true for no smoothing
|
|
1490
|
+
markers: false, // uncomment for debugging
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
|
|
1494
|
+
tl.fromTo(items,
|
|
1495
|
+
{ opacity: 0, y: 28 },
|
|
1496
|
+
{
|
|
1497
|
+
opacity: 1,
|
|
1498
|
+
y: 0,
|
|
1499
|
+
ease: 'power2.out',
|
|
1500
|
+
// Duration is ignored by scrub; timeline length maps to scroll distance.
|
|
1501
|
+
// Stagger distributes the items across the timeline for a nice cascade.
|
|
1502
|
+
stagger: { each: 0.12 }
|
|
1503
|
+
}
|
|
1504
|
+
);
|
|
1505
|
+
};
|
|
1506
|
+
|
|
1507
|
+
window.initPartnerVideos = function (container) {
|
|
1508
|
+
const items = Array.from(container.querySelectorAll('.partner_item'));
|
|
1509
|
+
const vids = items.map(i => i.querySelector('video')).filter(Boolean);
|
|
1510
|
+
|
|
1511
|
+
const pauseAll = (except) => {
|
|
1512
|
+
vids.forEach(v => {
|
|
1513
|
+
if (v !== except) {
|
|
1514
|
+
v.pause();
|
|
1515
|
+
v.muted = true;
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
};
|
|
1519
|
+
|
|
1520
|
+
items.forEach((item) => {
|
|
1521
|
+
const v = item.querySelector('video');
|
|
1522
|
+
if (!v) return;
|
|
1523
|
+
|
|
1524
|
+
v.controls = false;
|
|
1525
|
+
v.loop = false;
|
|
1526
|
+
v.muted = true;
|
|
1527
|
+
v.setAttribute('playsinline', '');
|
|
1528
|
+
v.playsInline = true;
|
|
1529
|
+
|
|
1530
|
+
item.addEventListener('click', () => {
|
|
1531
|
+
if (v.paused) {
|
|
1532
|
+
pauseAll(v);
|
|
1533
|
+
v.muted = false;
|
|
1534
|
+
v.play();
|
|
1535
|
+
} else {
|
|
1536
|
+
v.pause();
|
|
1537
|
+
}
|
|
1538
|
+
});
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
const rootEl =
|
|
1542
|
+
document.querySelector('[data-scroll-root]') ||
|
|
1543
|
+
document.querySelector('[data-smooth-scroll-root]') ||
|
|
1544
|
+
null;
|
|
1545
|
+
|
|
1546
|
+
const io = new IntersectionObserver(
|
|
1547
|
+
(entries) => {
|
|
1548
|
+
entries.forEach(({ isIntersecting, target }) => {
|
|
1549
|
+
const v = target.querySelector('video');
|
|
1550
|
+
if (!v) return;
|
|
1551
|
+
if (!isIntersecting) v.pause();
|
|
1552
|
+
});
|
|
1553
|
+
},
|
|
1554
|
+
{ root: rootEl, threshold: 0.25 }
|
|
1555
|
+
);
|
|
1556
|
+
|
|
1557
|
+
items.forEach((item) => io.observe(item));
|
|
1558
|
+
};
|
|
1559
|
+
|
|
1434
1560
|
|
|
1435
1561
|
|
|
1436
1562
|
// Case study - What's next interaction
|