@widelab-nc/widelab 1.1.33 → 1.1.35
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 +201 -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.35",
|
|
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
|
@@ -627,6 +627,52 @@ window.reviewsSlider = function(e) {
|
|
|
627
627
|
});
|
|
628
628
|
}
|
|
629
629
|
|
|
630
|
+
// Partner slider
|
|
631
|
+
window.partnerSlider = function (e) {
|
|
632
|
+
// Keep the same querySelector for consistency with teamSlider
|
|
633
|
+
const teamList = e.querySelector('.team_collection_list');
|
|
634
|
+
|
|
635
|
+
// Initialize Splide with drag restored
|
|
636
|
+
const splide = new Splide(e, {
|
|
637
|
+
type: 'slide',
|
|
638
|
+
fixedWidth: '20%',
|
|
639
|
+
padding: { left: '2.5rem', right: 0 },
|
|
640
|
+
focus: 0,
|
|
641
|
+
gap: 0,
|
|
642
|
+
pagination: true,
|
|
643
|
+
omitEnd: true,
|
|
644
|
+
arrows: false,
|
|
645
|
+
drag: true, // restored dragging
|
|
646
|
+
easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
|
|
647
|
+
snap: true,
|
|
648
|
+
classes: {
|
|
649
|
+
pagination: 'splide__pagination facts-pagination partner-bullets',
|
|
650
|
+
page: 'splide__pagination__page facts-page',
|
|
651
|
+
},
|
|
652
|
+
breakpoints: {
|
|
653
|
+
992: { fixedWidth: '40%', padding: { left: '1.75rem' }, drag: 'free', snap: false },
|
|
654
|
+
560: { fixedWidth: '75%', padding: { left: '1.375rem' }, drag: 'free', snap: false },
|
|
655
|
+
},
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
splide.mount();
|
|
659
|
+
|
|
660
|
+
// Removed: click-to-next handler
|
|
661
|
+
|
|
662
|
+
// GSAP in-view animation
|
|
663
|
+
gsap.from(e, {
|
|
664
|
+
scrollTrigger: {
|
|
665
|
+
trigger: e,
|
|
666
|
+
start: 'top bottom',
|
|
667
|
+
end: 'bottom bottom',
|
|
668
|
+
scrub: 1,
|
|
669
|
+
once: true,
|
|
670
|
+
},
|
|
671
|
+
x: '10%',
|
|
672
|
+
opacity: 0,
|
|
673
|
+
ease: 'linear',
|
|
674
|
+
});
|
|
675
|
+
};
|
|
630
676
|
// Element padding change on scroll
|
|
631
677
|
window.elementPaddingChange = function(e) {
|
|
632
678
|
gsap.to(e, {
|
|
@@ -1431,6 +1477,161 @@ window.servicesSliders = function(e) {
|
|
|
1431
1477
|
});
|
|
1432
1478
|
}
|
|
1433
1479
|
|
|
1480
|
+
// Play-once timeline: children fade-in from bottom with stagger
|
|
1481
|
+
window.initBentoRevealTimeline = function (container) {
|
|
1482
|
+
// Respect reduced motion
|
|
1483
|
+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
1484
|
+
container.querySelectorAll(':scope > *').forEach(el => {
|
|
1485
|
+
el.style.opacity = 1;
|
|
1486
|
+
el.style.transform = 'none';
|
|
1487
|
+
});
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
const items = Array.from(container.children); // direct children only
|
|
1492
|
+
|
|
1493
|
+
// Set initial state
|
|
1494
|
+
gsap.set(items, { opacity: 0, y: 24 });
|
|
1495
|
+
|
|
1496
|
+
// Build timeline that plays when scrolled into view
|
|
1497
|
+
const tl = gsap.timeline({
|
|
1498
|
+
scrollTrigger: {
|
|
1499
|
+
trigger: container,
|
|
1500
|
+
start: 'top 80%', // when top of container hits 80% of viewport
|
|
1501
|
+
end: 'bottom 40%', // not critical for play-only, but nice bounds
|
|
1502
|
+
toggleActions: 'play none none none',
|
|
1503
|
+
once: true
|
|
1504
|
+
}
|
|
1505
|
+
});
|
|
1506
|
+
|
|
1507
|
+
tl.to(items, {
|
|
1508
|
+
opacity: 1,
|
|
1509
|
+
y: 0,
|
|
1510
|
+
duration: 0.6,
|
|
1511
|
+
ease: 'power2.out',
|
|
1512
|
+
stagger: 0.12
|
|
1513
|
+
});
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1516
|
+
// Scrubbed timeline: progress tied to scroll progress
|
|
1517
|
+
window.initBentoRevealScrub = function (container) {
|
|
1518
|
+
// Respect reduced motion
|
|
1519
|
+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
1520
|
+
container.querySelectorAll(':scope > *').forEach(el => {
|
|
1521
|
+
el.style.opacity = 1;
|
|
1522
|
+
el.style.transform = 'none';
|
|
1523
|
+
});
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
const items = Array.from(container.children); // direct children only
|
|
1528
|
+
|
|
1529
|
+
// Important: define from state in timeline for scrub to interpolate smoothly
|
|
1530
|
+
const tl = gsap.timeline({
|
|
1531
|
+
scrollTrigger: {
|
|
1532
|
+
trigger: container,
|
|
1533
|
+
start: 'top 90%', // start easing in slightly later
|
|
1534
|
+
end: 'bottom 65%', // full reveal by near the end of container
|
|
1535
|
+
scrub: 0.5, // smoothing; use true for no smoothing
|
|
1536
|
+
markers: false, // uncomment for debugging
|
|
1537
|
+
}
|
|
1538
|
+
});
|
|
1539
|
+
|
|
1540
|
+
tl.fromTo(items,
|
|
1541
|
+
{ opacity: 0, y: 28 },
|
|
1542
|
+
{
|
|
1543
|
+
opacity: 1,
|
|
1544
|
+
y: 0,
|
|
1545
|
+
ease: 'power2.out',
|
|
1546
|
+
// Duration is ignored by scrub; timeline length maps to scroll distance.
|
|
1547
|
+
// Stagger distributes the items across the timeline for a nice cascade.
|
|
1548
|
+
stagger: { each: 0.12 }
|
|
1549
|
+
}
|
|
1550
|
+
);
|
|
1551
|
+
};
|
|
1552
|
+
window.initPartnerVideos = function (container) {
|
|
1553
|
+
const items = Array.from(container.querySelectorAll('.partner_item'));
|
|
1554
|
+
const vids = items.map(i => i.querySelector('video')).filter(Boolean);
|
|
1555
|
+
|
|
1556
|
+
// Helper: pause all other videos
|
|
1557
|
+
const pauseAll = (except) => {
|
|
1558
|
+
vids.forEach(v => {
|
|
1559
|
+
if (v !== except) {
|
|
1560
|
+
v.pause();
|
|
1561
|
+
v.muted = true;
|
|
1562
|
+
const parent = v.closest('.partner_item');
|
|
1563
|
+
if (parent) toggleIcons(parent, false);
|
|
1564
|
+
}
|
|
1565
|
+
});
|
|
1566
|
+
};
|
|
1567
|
+
|
|
1568
|
+
// Helper: toggle play/pause icons
|
|
1569
|
+
function toggleIcons(item, isPlaying) {
|
|
1570
|
+
const playIcon = item.querySelector('.is-play');
|
|
1571
|
+
const pauseIcon = item.querySelector('.is-pause');
|
|
1572
|
+
if (isPlaying) {
|
|
1573
|
+
if (playIcon) playIcon.style.display = 'none';
|
|
1574
|
+
if (pauseIcon) pauseIcon.style.display = 'block';
|
|
1575
|
+
} else {
|
|
1576
|
+
if (playIcon) playIcon.style.display = 'block';
|
|
1577
|
+
if (pauseIcon) pauseIcon.style.display = 'none';
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
items.forEach((item) => {
|
|
1582
|
+
const v = item.querySelector('video');
|
|
1583
|
+
if (!v) return;
|
|
1584
|
+
|
|
1585
|
+
v.controls = false;
|
|
1586
|
+
v.loop = false;
|
|
1587
|
+
v.muted = true;
|
|
1588
|
+
v.setAttribute('playsinline', '');
|
|
1589
|
+
v.playsInline = true;
|
|
1590
|
+
|
|
1591
|
+
// Default state on init (show play icon)
|
|
1592
|
+
toggleIcons(item, false);
|
|
1593
|
+
|
|
1594
|
+
// Handle click (play/pause toggle)
|
|
1595
|
+
item.addEventListener('click', () => {
|
|
1596
|
+
if (v.paused) {
|
|
1597
|
+
pauseAll(v);
|
|
1598
|
+
v.muted = false;
|
|
1599
|
+
v.play();
|
|
1600
|
+
toggleIcons(item, true);
|
|
1601
|
+
} else {
|
|
1602
|
+
v.pause();
|
|
1603
|
+
toggleIcons(item, false);
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1606
|
+
|
|
1607
|
+
// Handle pause and ended (ensure icons reset)
|
|
1608
|
+
v.addEventListener('pause', () => toggleIcons(item, false));
|
|
1609
|
+
v.addEventListener('ended', () => toggleIcons(item, false));
|
|
1610
|
+
v.addEventListener('play', () => toggleIcons(item, true));
|
|
1611
|
+
});
|
|
1612
|
+
|
|
1613
|
+
// Pause videos when out of viewport
|
|
1614
|
+
const rootEl =
|
|
1615
|
+
document.querySelector('[data-scroll-root]') ||
|
|
1616
|
+
document.querySelector('[data-smooth-scroll-root]') ||
|
|
1617
|
+
null;
|
|
1618
|
+
|
|
1619
|
+
const io = new IntersectionObserver(
|
|
1620
|
+
(entries) => {
|
|
1621
|
+
entries.forEach(({ isIntersecting, target }) => {
|
|
1622
|
+
const v = target.querySelector('video');
|
|
1623
|
+
if (!v) return;
|
|
1624
|
+
if (!isIntersecting) {
|
|
1625
|
+
v.pause();
|
|
1626
|
+
toggleIcons(target, false);
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
},
|
|
1630
|
+
{ root: rootEl, threshold: 0.25 }
|
|
1631
|
+
);
|
|
1632
|
+
|
|
1633
|
+
items.forEach((item) => io.observe(item));
|
|
1634
|
+
};
|
|
1434
1635
|
|
|
1435
1636
|
|
|
1436
1637
|
// Case study - What's next interaction
|