@widelab-nc/widelab 1.1.32 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@widelab-nc/widelab",
3
- "version": "1.1.32",
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
@@ -1324,6 +1324,73 @@ window.heroSliders = function(e) {
1324
1324
  }
1325
1325
 
1326
1326
 
1327
+ // Splide without GSAP; pagination inserted as first child INSIDE .splide
1328
+ window.awwwardsSliders = function (el) {
1329
+ if (el.dataset.splideInitialized === '1') return;
1330
+
1331
+ // 1) Find or create Splide root
1332
+ let root = el.classList?.contains('splide') ? el : el.closest?.('.splide');
1333
+ const track = el.querySelector?.('.splide__track') || el.closest?.('.splide__track');
1334
+
1335
+ if (!root && track) {
1336
+ root = document.createElement('div');
1337
+ root.className = 'splide testimonial';
1338
+ track.parentNode.insertBefore(root, track);
1339
+ root.appendChild(track);
1340
+ }
1341
+
1342
+ // 2) Validate structure
1343
+ if (!root || !root.querySelector('.splide__track') || !root.querySelector('.splide__list')) {
1344
+ console.warn('[awwwardsSliders] Missing required Splide structure.');
1345
+ return;
1346
+ }
1347
+
1348
+ // 3) Splide config
1349
+ const config = {
1350
+ type: 'loop',
1351
+ perPage: 1,
1352
+ perMove: 1,
1353
+ gap: '0px',
1354
+ arrows: false,
1355
+ pagination: true,
1356
+ drag: false,
1357
+ speed: 300,
1358
+ easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
1359
+ classes: {
1360
+ pagination: 'splide__pagination awwwards-pagination',
1361
+ page: 'splide__pagination__page awwwards-page',
1362
+ },
1363
+ breakpoints: {
1364
+ 992: { drag: true },
1365
+ },
1366
+ };
1367
+
1368
+ const splide = new Splide(root, config).mount();
1369
+
1370
+ // 4) Move pagination INSIDE .splide as FIRST child
1371
+ splide.on('pagination:mounted', (data) => {
1372
+ const list = data.list;
1373
+ if (list && root.firstChild) {
1374
+ root.insertBefore(list, root.firstChild);
1375
+ }
1376
+ });
1377
+
1378
+ // Fallback if pagination already exists
1379
+ queueMicrotask(() => {
1380
+ const list = root.querySelector('.splide__pagination');
1381
+ const track = root.querySelector('.splide__track');
1382
+ if (list && track && list.nextSibling !== track) {
1383
+ root.insertBefore(list, track);
1384
+ }
1385
+ });
1386
+
1387
+ // 5) Click-to-next on desktop
1388
+ if (window.innerWidth > 992) {
1389
+ root.addEventListener('click', () => splide.go('+1'));
1390
+ }
1391
+
1392
+ el.dataset.splideInitialized = '1';
1393
+ };
1327
1394
 
1328
1395
  // Sliders on Services page
1329
1396
  window.servicesSliders = function(e) {
@@ -1364,6 +1431,132 @@ window.servicesSliders = function(e) {
1364
1431
  });
1365
1432
  }
1366
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
+
1367
1560
 
1368
1561
 
1369
1562
  // Case study - What's next interaction