@widelab-nc/widelab 1.1.47 → 1.1.49

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/src/index.js CHANGED
@@ -116,25 +116,25 @@ function contactFormOpenAnimation() {
116
116
  }
117
117
 
118
118
  //Smooth scroll init
119
- const lenis = new Lenis({
120
- duration: 1.2,
121
- easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
122
- });
123
- function lenisScroll() {
124
- lenis.on('scroll', ScrollTrigger.update);
125
- gsap.ticker.add((time)=>{
126
- lenis.raf(time * 1000)
127
- })
128
- gsap.ticker.lagSmoothing(0)
129
- function raf(time) {
130
- lenis.raf(time);
131
- requestAnimationFrame(raf);
132
- }
119
+ const lenis = new Lenis({
120
+ duration: 1.2,
121
+ easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
122
+ });
123
+ function lenisScroll() {
124
+ lenis.on('scroll', ScrollTrigger.update);
125
+ gsap.ticker.add((time)=>{
126
+ lenis.raf(time * 1000)
127
+ })
128
+ gsap.ticker.lagSmoothing(0)
129
+ function raf(time) {
130
+ lenis.raf(time);
133
131
  requestAnimationFrame(raf);
134
132
  }
133
+ requestAnimationFrame(raf);
134
+ }
135
135
 
136
- // Lazy load videos
137
- function lazyLoadVideos() {
136
+ // Lazy load videos
137
+ function lazyLoadVideos() {
138
138
  let lazyVideos = [].slice.call(document.querySelectorAll("video.lazyload"));
139
139
  if ("IntersectionObserver" in window) {
140
140
  let lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
@@ -155,54 +155,54 @@ function contactFormOpenAnimation() {
155
155
  }
156
156
  }
157
157
 
158
- // Reload page on browser back action
159
- function reloadOnBack() {
160
- window.addEventListener('pageshow', function (event) {
161
- if (event.persisted) {
162
- window.location.reload();
163
- }
164
- });
165
- }
158
+ // Reload page on browser back action
159
+ function reloadOnBack() {
160
+ window.addEventListener('pageshow', function (event) {
161
+ if (event.persisted) {
162
+ window.location.reload();
163
+ }
164
+ });
165
+ }
166
166
 
167
- // Scroll disable when mobile menu opened
168
- function disableScrollMenu() {
169
- function observeNavOverlay() {
170
- const target = document.querySelector('.w-nav-overlay');
171
- const config = { attributes: true, attributeFilter: ['style'] };
172
- const callback = function(mutationsList, observer) {
173
- for(const mutation of mutationsList) {
174
- if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
175
- const displayValue = target.style.display;
176
- if (displayValue === 'none') {
177
- document.body.classList.remove('is-scroll-off');
178
- lenis.start();
179
- } else {
180
- document.body.classList.add('is-scroll-off');
181
- lenis.stop();
182
- }
167
+ // Scroll disable when mobile menu opened
168
+ function disableScrollMenu() {
169
+ function observeNavOverlay() {
170
+ const target = document.querySelector('.w-nav-overlay');
171
+ const config = { attributes: true, attributeFilter: ['style'] };
172
+ const callback = function(mutationsList, observer) {
173
+ for(const mutation of mutationsList) {
174
+ if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
175
+ const displayValue = target.style.display;
176
+ if (displayValue === 'none') {
177
+ document.body.classList.remove('is-scroll-off');
178
+ lenis.start();
179
+ } else {
180
+ document.body.classList.add('is-scroll-off');
181
+ lenis.stop();
183
182
  }
184
183
  }
185
- };
186
- const observer = new MutationObserver(callback);
187
- observer.observe(target, config);
188
- }
189
- observeNavOverlay();
184
+ }
185
+ };
186
+ const observer = new MutationObserver(callback);
187
+ observer.observe(target, config);
190
188
  }
189
+ observeNavOverlay();
190
+ }
191
191
 
192
- // Hero move to reveal footer
193
- function revealFooter() {
194
- const footer = document.querySelector('.is-footer');
195
- if (footer) {
196
- gsap.to('#heroSection', {
197
- scrollTrigger: {
198
- trigger: '#bottomWrapper',
199
- start: 'top bottom',
200
- toggleActions: 'restart none none reverse',
201
- },
202
- autoAlpha: 0,
203
- });
204
- }
192
+ // Hero move to reveal footer
193
+ function revealFooter() {
194
+ const footer = document.querySelector('.is-footer');
195
+ if (footer) {
196
+ gsap.to('#heroSection', {
197
+ scrollTrigger: {
198
+ trigger: '#bottomWrapper',
199
+ start: 'top bottom',
200
+ toggleActions: 'restart none none reverse',
201
+ },
202
+ autoAlpha: 0,
203
+ });
205
204
  }
205
+ }
206
206
 
207
207
  // Page load animation (no-op below 992px)
208
208
  function pageLoadAnimation() {
@@ -273,9 +273,9 @@ function pageTransitionAnimation() {
273
273
  }
274
274
  });
275
275
  }
276
- // Header on scroll animation
276
+ // Header on scroll animation
277
277
  const infoBar = document.querySelector('.info-bar');
278
- const showHideHeader = gsap.timeline({ paused: true,})
278
+ const showHideHeader = gsap.timeline({ paused: true,})
279
279
  showHideHeader.to('.navbar', {
280
280
  y: '-100%',
281
281
  duration: 0.2,
@@ -288,19 +288,19 @@ if (infoBar) {
288
288
  ease: 'loader2',
289
289
  }, "<") }
290
290
 
291
- // Custom cursor on mousedown and mouseup
292
- function customCursorOnClick() {
293
- const cursorElements = document.querySelectorAll('[wide="customCursor"]');
294
- const customCursor = document.querySelector('.custom_cursor');
295
- cursorElements.forEach((element) => {
296
- element.addEventListener('mousedown', function () {
297
- customCursor.style.transform = 'scale3d(0.8, 0.8, 1)';
298
- });
299
- element.addEventListener('mouseup', function () {
300
- customCursor.style.transform = 'scale3d(1, 1, 1)';
301
- });
291
+ // Custom cursor on mousedown and mouseup
292
+ function customCursorOnClick() {
293
+ const cursorElements = document.querySelectorAll('[wide="customCursor"]');
294
+ const customCursor = document.querySelector('.custom_cursor');
295
+ cursorElements.forEach((element) => {
296
+ element.addEventListener('mousedown', function () {
297
+ customCursor.style.transform = 'scale3d(0.8, 0.8, 1)';
302
298
  });
303
- }
299
+ element.addEventListener('mouseup', function () {
300
+ customCursor.style.transform = 'scale3d(1, 1, 1)';
301
+ });
302
+ });
303
+ }
304
304
 
305
305
  // === SKILLS TRIGGER HARD-FIX (drop-in) ===
306
306
  (function () {
@@ -410,43 +410,43 @@ if (infoBar) {
410
410
  }
411
411
  })();
412
412
 
413
- // Header scroll trigger
414
- window.standardHeaderScrollAnimation = function() {
415
- ScrollTrigger.create({
416
- start: 'top top',
417
- endTrigger: '.bottom-wrapper',
418
- end: 'bottom bottom',
419
- onUpdate: (self) => {
420
- self.direction === 1 ? showHideHeader.play() : showHideHeader.reverse();
421
- },
422
- });
423
- }
413
+ // Header scroll trigger
414
+ window.standardHeaderScrollAnimation = function() {
415
+ ScrollTrigger.create({
416
+ start: 'top top',
417
+ endTrigger: '.bottom-wrapper',
418
+ end: 'bottom bottom',
419
+ onUpdate: (self) => {
420
+ self.direction === 1 ? showHideHeader.play() : showHideHeader.reverse();
421
+ },
422
+ });
423
+ }
424
424
 
425
- // Place video inside the text
426
- window.videoInsideText = function(e) {
425
+ // Place video inside the text
426
+ window.videoInsideText = function(e) {
427
427
  const headlineContent = e.querySelector('[class*="copy-this"]');
428
428
  const headlineSpan = e.querySelector('[class*="headline-span"]');
429
429
  headlineSpan.appendChild(headlineContent);
430
430
  }
431
431
 
432
- // Span video mask animation
433
- window.spanVideoMaskAnimation = function(e) {
434
- gsap.to(e, {
435
- scrollTrigger: { trigger: e, start: 'bottom bottom-=5%' },
436
- width: 0,
437
- ease: 'loader2',
438
- duration: 0.6,
439
- });
440
- }
432
+ // Span video mask animation
433
+ window.spanVideoMaskAnimation = function(e) {
434
+ gsap.to(e, {
435
+ scrollTrigger: { trigger: e, start: 'bottom bottom-=5%' },
436
+ width: 0,
437
+ ease: 'loader2',
438
+ duration: 0.6,
439
+ });
440
+ }
441
441
 
442
- // Custom cursor text change
443
- window.customCursorText = function(e) {
444
- e.addEventListener('mouseenter', () => {
445
- const wideCursorTextValue = e.getAttribute('wideCursorText');
446
- const customCursorTextElement = document.querySelector('.custom_cursor_text');
447
- customCursorTextElement.innerHTML = wideCursorTextValue;
448
- });
449
- }
442
+ // Custom cursor text change
443
+ window.customCursorText = function(e) {
444
+ e.addEventListener('mouseenter', () => {
445
+ const wideCursorTextValue = e.getAttribute('wideCursorText');
446
+ const customCursorTextElement = document.querySelector('.custom_cursor_text');
447
+ customCursorTextElement.innerHTML = wideCursorTextValue;
448
+ });
449
+ }
450
450
 
451
451
  let articleModalOpen;
452
452
  function articleModalOpenAnimation() {
@@ -550,6 +550,7 @@ window.hueAwardsAnimation = function(e) {
550
550
  };
551
551
 
552
552
 
553
+
553
554
  window.expandableProcessSticky = function (e) {
554
555
  var wrapper = e;
555
556
  if (!wrapper || wrapper.dataset.expandableProcessStickyInit === 'true') return;
@@ -559,8 +560,10 @@ window.expandableProcessSticky = function (e) {
559
560
  var count = items.length;
560
561
  if (count === 0) return;
561
562
 
563
+ var mq = window.matchMedia('(max-width: 991px)');
562
564
  var currentActive = -1;
563
565
  var ticking = false;
566
+ var isEnabled = false;
564
567
 
565
568
  function setActive(index) {
566
569
  if (index === currentActive) return;
@@ -594,9 +597,87 @@ window.expandableProcessSticky = function (e) {
594
597
  }
595
598
  }
596
599
 
597
- window.addEventListener('scroll', onScrollOrResize, { passive: true });
598
- window.addEventListener('resize', onResize);
599
- update();
600
+ // Click the row (number + title) to scroll to the trigger point that opens this item.
601
+ // Ignore clicks that originate inside the already-open .process-item panel (e.g. reading
602
+ // the description or clicking a link inside it shouldn't re-trigger a scroll).
603
+ function scrollToIndex(index) {
604
+ var rect = wrapper.getBoundingClientRect();
605
+ var absoluteTop = rect.top + window.pageYOffset;
606
+ var total = wrapper.offsetHeight - window.innerHeight;
607
+ if (total <= 0) return;
608
+ var progress = (index + 0.5) / (count + 1);
609
+ var targetY = absoluteTop + progress * total;
610
+
611
+ lenis.scrollTo(targetY, {
612
+ duration: 1.2,
613
+ easing: function (t) { return Math.min(1, 1.001 - Math.pow(2, -10 * t)); },
614
+ });
615
+ }
616
+
617
+ function onTabClick(event, index) {
618
+ if (event.target.closest('.process-item')) return;
619
+ scrollToIndex(index);
620
+ }
621
+
622
+ var tabClickHandlers = [];
623
+
624
+ function enable() {
625
+ if (isEnabled) return;
626
+ isEnabled = true;
627
+
628
+ for (var i = 0; i < items.length; i++) {
629
+ (function (index) {
630
+ var tab = items[index].closest('.process-wrapper');
631
+ if (!tab) return;
632
+ var handler = function (event) { onTabClick(event, index); };
633
+ tabClickHandlers[index] = { tab: tab, handler: handler };
634
+ tab.addEventListener('click', handler);
635
+ })(i);
636
+ }
637
+
638
+ window.addEventListener('scroll', onScrollOrResize, { passive: true });
639
+ window.addEventListener('resize', onResize);
640
+ update();
641
+ }
642
+
643
+ function disable() {
644
+ if (!isEnabled) return;
645
+ isEnabled = false;
646
+
647
+ window.removeEventListener('scroll', onScrollOrResize);
648
+ window.removeEventListener('resize', onResize);
649
+
650
+ for (var i = 0; i < tabClickHandlers.length; i++) {
651
+ var entry = tabClickHandlers[i];
652
+ if (entry) entry.tab.removeEventListener('click', entry.handler);
653
+ }
654
+ tabClickHandlers = [];
655
+
656
+ // Reset inline styles so mobile falls back to default CSS state.
657
+ for (var j = 0; j < items.length; j++) {
658
+ items[j].classList.remove('is-active');
659
+ items[j].style.height = '';
660
+ }
661
+ currentActive = -1;
662
+ }
663
+
664
+ function handleBreakpointChange(mql) {
665
+ if (mql.matches) {
666
+ // Mobile (<=991px): fully disabled.
667
+ disable();
668
+ } else {
669
+ enable();
670
+ }
671
+ }
672
+
673
+ handleBreakpointChange(mq);
674
+
675
+ if (mq.addEventListener) {
676
+ mq.addEventListener('change', handleBreakpointChange);
677
+ } else if (mq.addListener) {
678
+ // Safari fallback
679
+ mq.addListener(handleBreakpointChange);
680
+ }
600
681
  };
601
682
 
602
683
 
@@ -651,9 +732,6 @@ window.faqDropdowns = function (e) {
651
732
  };
652
733
 
653
734
 
654
-
655
-
656
-
657
735
  window.navbarThemeWatcher = function () {
658
736
  function checkNavbarTheme() {
659
737
  var stack = document.elementsFromPoint(window.innerWidth / 2, 20);
@@ -681,9 +759,6 @@ window.navbarThemeWatcher = function () {
681
759
 
682
760
 
683
761
 
684
-
685
-
686
-
687
762
  window.stickyServices = function (e) {
688
763
  var wrapper = e;
689
764
  if (!wrapper || wrapper.dataset.stickyServicesInit === 'true') return;
@@ -691,12 +766,25 @@ window.stickyServices = function (e) {
691
766
 
692
767
  var navItems = wrapper.querySelectorAll('.services_item-wrapper.is-animated');
693
768
  var stackItems = wrapper.querySelectorAll('.services-stack-img');
769
+ var mobileHandlers = wrapper.querySelectorAll('.mobile-handler');
694
770
 
695
771
  var count = Math.min(navItems.length, stackItems.length);
696
772
  if (count === 0) return;
697
773
 
774
+ // Copy each desktop .service-desc block into its matching .mobile-handler once,
775
+ // so editors only maintain the desktop copy and mobile text stays in sync.
776
+ for (var m = 0; m < count; m++) {
777
+ var sourceDesc = stackItems[m].querySelector('.service-desc');
778
+ var mobileContent = mobileHandlers[m] ? mobileHandlers[m].querySelector('.mobile-content-wrapper') : null;
779
+ if (sourceDesc && mobileContent && !mobileContent.querySelector('.service-desc')) {
780
+ var clonedDesc = sourceDesc.cloneNode(true);
781
+ mobileContent.insertBefore(clonedDesc, mobileContent.firstChild);
782
+ }
783
+ }
784
+
698
785
  var currentActive = -1;
699
786
  var displayedProgress = 0;
787
+ var pendingIndex = -1; // set while a click-triggered scroll is animating
700
788
 
701
789
  function setActive(index) {
702
790
  if (index === currentActive) return;
@@ -707,6 +795,12 @@ window.stickyServices = function (e) {
707
795
  for (var j = 0; j < stackItems.length; j++) {
708
796
  stackItems[j].classList.toggle('is-active', j === index);
709
797
  }
798
+ // Mirror the same active state on the mobile accordion panels
799
+ for (var k = 0; k < mobileHandlers.length; k++) {
800
+ var isTarget = k === index;
801
+ mobileHandlers[k].classList.toggle('is-active', isTarget);
802
+ mobileHandlers[k].style.height = isTarget ? mobileHandlers[k].scrollHeight + 'px' : '0px';
803
+ }
710
804
  }
711
805
 
712
806
  function getTargetProgress() {
@@ -719,6 +813,21 @@ window.stickyServices = function (e) {
719
813
 
720
814
  function loop() {
721
815
  var target = getTargetProgress();
816
+
817
+ // While a click-triggered scroll is in flight, keep the clicked tab
818
+ // forced active instead of letting the lerp below pull it back to the
819
+ // tab that matches the not-yet-moved real scroll position.
820
+ if (pendingIndex !== -1) {
821
+ var pendingProgress = (pendingIndex + 0.5) / count;
822
+ if (Math.abs(target - pendingProgress) < 0.02) {
823
+ pendingIndex = -1;
824
+ } else {
825
+ setActive(pendingIndex);
826
+ requestAnimationFrame(loop);
827
+ return;
828
+ }
829
+ }
830
+
722
831
  displayedProgress += (target - displayedProgress) * 0.18;
723
832
  if (Math.abs(target - displayedProgress) < 0.001) {
724
833
  displayedProgress = target;
@@ -728,10 +837,44 @@ window.stickyServices = function (e) {
728
837
  requestAnimationFrame(loop);
729
838
  }
730
839
 
731
- loop();
732
- };
840
+ // Click a tab to scroll to the point where it becomes active, forcing it
841
+ // active immediately instead of waiting for the scroll animation to finish.
842
+ function scrollToIndex(index) {
843
+ var rect = wrapper.getBoundingClientRect();
844
+ var absoluteTop = rect.top + window.pageYOffset;
845
+ var total = wrapper.offsetHeight - window.innerHeight;
846
+ if (total <= 0) return;
847
+ var progress = (index + 0.5) / count;
848
+ var targetY = absoluteTop + progress * total;
849
+
850
+ pendingIndex = index;
851
+ displayedProgress = progress;
852
+ setActive(index);
853
+
854
+ lenis.scrollTo(targetY, {
855
+ duration: 1.2,
856
+ easing: function (t) { return Math.min(1, 1.001 - Math.pow(2, -10 * t)); },
857
+ });
858
+ }
733
859
 
860
+ for (var n = 0; n < navItems.length; n++) {
861
+ (function (index) {
862
+ navItems[index].addEventListener('click', function () {
863
+ scrollToIndex(index);
864
+ });
865
+ })(n);
866
+ }
867
+
868
+ // Keep the open mobile panel's height correct if its content reflows on resize
869
+ function onResize() {
870
+ if (currentActive === -1) return;
871
+ var openHandler = mobileHandlers[currentActive];
872
+ if (openHandler) openHandler.style.height = openHandler.scrollHeight + 'px';
873
+ }
874
+ window.addEventListener('resize', onResize);
734
875
 
876
+ loop();
877
+ };
735
878
 
736
879
 
737
880
 
@@ -845,8 +988,6 @@ window.heroAnimationOnLoad = function(e) {
845
988
  };
846
989
 
847
990
 
848
-
849
-
850
991
  // Case study mask animation + pill fade-in (full, iOS-safe, L->R reveal)
851
992
  window.caseStudyInteraction = function (e) {
852
993
  const mask = e.querySelector('.portfolio_item_image-mask');
@@ -928,220 +1069,219 @@ window.caseStudyInteraction = function (e) {
928
1069
  };
929
1070
 
930
1071
 
1072
+ // Reviews slider
1073
+ window.reviewsSlider = function(e) {
1074
+ // Put content of static slide into list
1075
+ const staticContent = e.querySelector(
1076
+ '.splide__slide.reviews_collection_item.is-static'
1077
+ ).innerHTML;
1078
+ const dynamicElement = e.querySelector('.reviews_collection_item');
1079
+ dynamicElement.innerHTML = staticContent;
1080
+ dynamicElement.classList.add('is-static');
931
1081
 
932
- // Reviews slider
933
- window.reviewsSlider = function(e) {
934
- // Put content of static slide into list
935
- const staticContent = e.querySelector(
936
- '.splide__slide.reviews_collection_item.is-static'
937
- ).innerHTML;
938
- const dynamicElement = e.querySelector('.reviews_collection_item');
939
- dynamicElement.innerHTML = staticContent;
940
- dynamicElement.classList.add('is-static');
941
-
942
- // Init reviews splide
943
- const reviewsSplide = new Splide(e, {
944
- type: 'slide',
945
- fixedWidth: '24.5rem',
946
- rewind: true,
947
- focus: 0,
948
- padding: { left: '2.5rem', right: 0 },
949
- gap: 0,
950
- omitEnd: true,
951
- arrows: false,
952
- drag: false,
953
- easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
954
- snap: true,
955
- classes: {
956
- pagination: 'splide__pagination reviews-pagination',
957
- page: 'splide__pagination__page reviews-page',
958
- },
959
- breakpoints: {
960
- 992: { fixedWidth: '17.438rem', padding: { left: '1.75rem' }, drag: 'free', snap: false },
961
- 480: { fixedWidth: '16.25rem', padding: { left: '1.375rem' }},
962
- },
963
- }).mount();
964
-
965
- // Next slide on click
966
- if (window.innerWidth > 992) {
967
- reviewsSplide.on('click', function () {
968
- reviewsSplide.go('+1');
969
- });
970
- }
1082
+ // Init reviews splide
1083
+ const reviewsSplide = new Splide(e, {
1084
+ type: 'slide',
1085
+ fixedWidth: '24.5rem',
1086
+ rewind: true,
1087
+ focus: 0,
1088
+ padding: { left: '2.5rem', right: 0 },
1089
+ gap: 0,
1090
+ omitEnd: true,
1091
+ arrows: false,
1092
+ drag: false,
1093
+ easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
1094
+ snap: true,
1095
+ classes: {
1096
+ pagination: 'splide__pagination reviews-pagination',
1097
+ page: 'splide__pagination__page reviews-page',
1098
+ },
1099
+ breakpoints: {
1100
+ 992: { fixedWidth: '17.438rem', padding: { left: '1.75rem' }, drag: 'free', snap: false },
1101
+ 480: { fixedWidth: '16.25rem', padding: { left: '1.375rem' }},
1102
+ },
1103
+ }).mount();
971
1104
 
972
- // Animation in
973
- gsap.from(e, {
974
- scrollTrigger: {
975
- trigger: e,
976
- start: 'top bottom',
977
- end: 'bottom bottom-=15%',
978
- scrub: 1,
979
- once: true,
980
- },
981
- x: '10%',
982
- opacity: 0,
983
- ease: 'linear',
1105
+ // Next slide on click
1106
+ if (window.innerWidth > 992) {
1107
+ reviewsSplide.on('click', function () {
1108
+ reviewsSplide.go('+1');
984
1109
  });
985
1110
  }
986
1111
 
987
- // Facts slider
988
- window.factsSlider = function(e) {
989
- // Facts slider splide initialize
990
- const factsSplide = new Splide(e, {
991
- type: 'loop',
992
- perPage: 1,
993
- gap: 0,
994
- arrows: false,
995
- drag: false,
996
- duration: 0.15,
997
- easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
998
- classes: {
999
- pagination: 'splide__pagination facts-pagination',
1000
- page: 'splide__pagination__page facts-page',
1001
- },
1002
- breakpoints: {
1003
- 992: { gap: '1.75rem', drag: true },
1004
- 480: { gap: '1.375rem' },
1005
- },
1006
- }).mount();
1007
- // Next on click
1008
- if (window.innerWidth > 992) {
1009
- factsSplide.on('click', function () {
1010
- factsSplide.go('+1');
1011
- });
1012
- }
1112
+ // Animation in
1113
+ gsap.from(e, {
1114
+ scrollTrigger: {
1115
+ trigger: e,
1116
+ start: 'top bottom',
1117
+ end: 'bottom bottom-=15%',
1118
+ scrub: 1,
1119
+ once: true,
1120
+ },
1121
+ x: '10%',
1122
+ opacity: 0,
1123
+ ease: 'linear',
1124
+ });
1125
+ }
1013
1126
 
1014
- // Click on external link
1015
- const externalLink = e.querySelectorAll('.external_link.is-cursor');
1016
- // Loop through each element and execute customCursorIn.reverse()
1017
- externalLink.forEach((link) => {
1018
- link.addEventListener('click', () => {
1019
- event.stopPropagation();
1020
- });
1127
+ // Facts slider
1128
+ window.factsSlider = function(e) {
1129
+ // Facts slider splide initialize
1130
+ const factsSplide = new Splide(e, {
1131
+ type: 'loop',
1132
+ perPage: 1,
1133
+ gap: 0,
1134
+ arrows: false,
1135
+ drag: false,
1136
+ duration: 0.15,
1137
+ easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
1138
+ classes: {
1139
+ pagination: 'splide__pagination facts-pagination',
1140
+ page: 'splide__pagination__page facts-page',
1141
+ },
1142
+ breakpoints: {
1143
+ 992: { gap: '1.75rem', drag: true },
1144
+ 480: { gap: '1.375rem' },
1145
+ },
1146
+ }).mount();
1147
+ // Next on click
1148
+ if (window.innerWidth > 992) {
1149
+ factsSplide.on('click', function () {
1150
+ factsSplide.go('+1');
1021
1151
  });
1152
+ }
1022
1153
 
1023
- // Animations
1024
- // Function to play video on the active slide
1025
- function playActiveSlideVideo(newIndex) {
1026
- var activeSlide = factsSplide.Components.Elements.slides[newIndex];
1027
- var activeVideo = activeSlide.querySelector('video');
1028
- if (activeVideo) {
1029
- activeVideo.play();
1030
- }
1031
- }
1032
-
1033
- // Function to pause and rewind videos on inactive slides
1034
- function pauseAndRewindInactiveVideos(newIndex) {
1035
- var slides = factsSplide.Components.Elements.slides;
1036
- slides.forEach(function (slide, index) {
1037
- var video = slide.querySelector('video');
1038
- if (video && index !== newIndex) {
1039
- video.pause();
1040
- video.currentTime = 0; // rewind the video
1041
- }
1042
- });
1043
- }
1044
- // Function to animate elements on the active slide
1045
- function animateSlideElements(slide) {
1046
- gsap.fromTo(
1047
- [
1048
- slide.querySelector('.is-h4'),
1049
- slide.querySelector('.facts-slide_legend-wrapper'),
1050
- slide.querySelector('.facts-slide_diagram-wrapper'),
1051
- slide.querySelector('.facts-slide_source')
1052
- ],
1053
- {
1054
- x: '2rem',
1055
- opacity: 0
1056
- },
1057
- {
1058
- x: '0',
1059
- opacity: 1,
1060
- stagger: 0.2,
1061
- duration: 0.5,
1062
- easing: 'loader2'
1063
- }
1064
- );
1065
- }
1066
- // Function to reset animation for the elements in the slide
1067
- function resetSlideAnimation(slide) {
1068
- gsap.set(
1069
- [
1070
- slide.querySelector('.is-h4'),
1071
- slide.querySelector('.facts-slide_legend-wrapper'),
1072
- slide.querySelector('.facts-slide_diagram-wrapper'),
1073
- slide.querySelector('.facts-slide_source')
1074
- ],
1075
- {
1076
- x: '2rem',
1077
- opacity: 0
1078
- }
1079
- );
1080
- }
1081
- // Event listener for 'move' event
1082
- factsSplide.on('move', function (newIndex) {
1083
- playActiveSlideVideo(newIndex);
1084
- var activeSlide = factsSplide.Components.Elements.slides[newIndex];
1085
- animateSlideElements(activeSlide);
1086
- });
1087
- // Event listener for 'moved' event
1088
- factsSplide.on('moved', function (oldIndex) {
1089
- pauseAndRewindInactiveVideos(oldIndex);
1090
- var previousSlide = factsSplide.Components.Elements.slides[oldIndex];
1091
- resetSlideAnimation(previousSlide);
1154
+ // Click on external link
1155
+ const externalLink = e.querySelectorAll('.external_link.is-cursor');
1156
+ // Loop through each element and execute customCursorIn.reverse()
1157
+ externalLink.forEach((link) => {
1158
+ link.addEventListener('click', () => {
1159
+ event.stopPropagation();
1092
1160
  });
1161
+ });
1093
1162
 
1163
+ // Animations
1164
+ // Function to play video on the active slide
1165
+ function playActiveSlideVideo(newIndex) {
1166
+ var activeSlide = factsSplide.Components.Elements.slides[newIndex];
1167
+ var activeVideo = activeSlide.querySelector('video');
1168
+ if (activeVideo) {
1169
+ activeVideo.play();
1170
+ }
1094
1171
  }
1095
1172
 
1096
- // Team slider
1097
- window.teamSlider = function(e) {
1098
- // Randomize order of slides
1099
- const teamList = e.querySelector('.team_collection_list');
1100
- const teamItems = Array.from(teamList.children);
1101
- teamItems.sort(function () {
1102
- return 0.5 - Math.random();
1103
- });
1104
- teamItems.forEach(function (item) {
1105
- teamList.appendChild(item);
1173
+ // Function to pause and rewind videos on inactive slides
1174
+ function pauseAndRewindInactiveVideos(newIndex) {
1175
+ var slides = factsSplide.Components.Elements.slides;
1176
+ slides.forEach(function (slide, index) {
1177
+ var video = slide.querySelector('video');
1178
+ if (video && index !== newIndex) {
1179
+ video.pause();
1180
+ video.currentTime = 0; // rewind the video
1181
+ }
1106
1182
  });
1107
-
1108
- // Team slider splide initialize
1109
- new Splide(e, {
1110
- type: 'slide',
1111
- fixedWidth: '20%',
1112
- padding: { left: '2.5rem', right: 0 },
1113
- focus: 0,
1114
- gap: 0,
1115
- pagination: false,
1116
- omitEnd: true,
1117
- arrows: false,
1118
- drag: true,
1119
- easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
1120
- snap: true,
1121
- classes: {
1122
- pagination: 'splide__pagination facts-pagination',
1123
- page: 'splide__pagination__page facts-page',
1124
- },
1125
- breakpoints: {
1126
- 992: { fixedWidth: '40%', padding: { left: '1.75rem' }, drag: 'free', snap: false },
1127
- 560: { fixedWidth: '75%', padding: { left: '1.375rem' }, drag: 'free', snap: false },
1128
- },
1129
- }).mount();
1130
-
1131
- // Animation in
1132
- gsap.from(e, {
1133
- scrollTrigger: {
1134
- trigger: e,
1135
- start: 'top bottom',
1136
- end: 'bottom bottom',
1137
- scrub: 1,
1138
- once: true,
1183
+ }
1184
+ // Function to animate elements on the active slide
1185
+ function animateSlideElements(slide) {
1186
+ gsap.fromTo(
1187
+ [
1188
+ slide.querySelector('.is-h4'),
1189
+ slide.querySelector('.facts-slide_legend-wrapper'),
1190
+ slide.querySelector('.facts-slide_diagram-wrapper'),
1191
+ slide.querySelector('.facts-slide_source')
1192
+ ],
1193
+ {
1194
+ x: '2rem',
1195
+ opacity: 0
1139
1196
  },
1140
- x: '10%',
1141
- opacity: 0,
1142
- ease: 'linear',
1143
- });
1197
+ {
1198
+ x: '0',
1199
+ opacity: 1,
1200
+ stagger: 0.2,
1201
+ duration: 0.5,
1202
+ easing: 'loader2'
1203
+ }
1204
+ );
1205
+ }
1206
+ // Function to reset animation for the elements in the slide
1207
+ function resetSlideAnimation(slide) {
1208
+ gsap.set(
1209
+ [
1210
+ slide.querySelector('.is-h4'),
1211
+ slide.querySelector('.facts-slide_legend-wrapper'),
1212
+ slide.querySelector('.facts-slide_diagram-wrapper'),
1213
+ slide.querySelector('.facts-slide_source')
1214
+ ],
1215
+ {
1216
+ x: '2rem',
1217
+ opacity: 0
1218
+ }
1219
+ );
1144
1220
  }
1221
+ // Event listener for 'move' event
1222
+ factsSplide.on('move', function (newIndex) {
1223
+ playActiveSlideVideo(newIndex);
1224
+ var activeSlide = factsSplide.Components.Elements.slides[newIndex];
1225
+ animateSlideElements(activeSlide);
1226
+ });
1227
+ // Event listener for 'moved' event
1228
+ factsSplide.on('moved', function (oldIndex) {
1229
+ pauseAndRewindInactiveVideos(oldIndex);
1230
+ var previousSlide = factsSplide.Components.Elements.slides[oldIndex];
1231
+ resetSlideAnimation(previousSlide);
1232
+ });
1233
+
1234
+ }
1235
+
1236
+ // Team slider
1237
+ window.teamSlider = function(e) {
1238
+ // Randomize order of slides
1239
+ const teamList = e.querySelector('.team_collection_list');
1240
+ const teamItems = Array.from(teamList.children);
1241
+ teamItems.sort(function () {
1242
+ return 0.5 - Math.random();
1243
+ });
1244
+ teamItems.forEach(function (item) {
1245
+ teamList.appendChild(item);
1246
+ });
1247
+
1248
+ // Team slider splide initialize
1249
+ new Splide(e, {
1250
+ type: 'slide',
1251
+ fixedWidth: '20%',
1252
+ padding: { left: '2.5rem', right: 0 },
1253
+ focus: 0,
1254
+ gap: 0,
1255
+ pagination: false,
1256
+ omitEnd: true,
1257
+ arrows: false,
1258
+ drag: true,
1259
+ easing: 'cubic-bezier(0.83, 0, 0.17, 1)',
1260
+ snap: true,
1261
+ classes: {
1262
+ pagination: 'splide__pagination facts-pagination',
1263
+ page: 'splide__pagination__page facts-page',
1264
+ },
1265
+ breakpoints: {
1266
+ 992: { fixedWidth: '40%', padding: { left: '1.75rem' }, drag: 'free', snap: false },
1267
+ 560: { fixedWidth: '75%', padding: { left: '1.375rem' }, drag: 'free', snap: false },
1268
+ },
1269
+ }).mount();
1270
+
1271
+ // Animation in
1272
+ gsap.from(e, {
1273
+ scrollTrigger: {
1274
+ trigger: e,
1275
+ start: 'top bottom',
1276
+ end: 'bottom bottom',
1277
+ scrub: 1,
1278
+ once: true,
1279
+ },
1280
+ x: '10%',
1281
+ opacity: 0,
1282
+ ease: 'linear',
1283
+ });
1284
+ }
1145
1285
 
1146
1286
  // Partner slider
1147
1287
  window.partnerSlider = function (e) {
@@ -1189,68 +1329,68 @@ window.partnerSlider = function (e) {
1189
1329
  ease: 'linear',
1190
1330
  });
1191
1331
  };
1192
- // Element padding change on scroll
1193
- window.elementPaddingChange = function(e) {
1194
- gsap.to(e, {
1195
- scrollTrigger: {
1196
- trigger: e,
1197
- start: 'top bottom',
1198
- end: 'top top',
1199
- toggleActions: 'restart none none reverse',
1200
- scrub: 1,
1332
+ // Element padding change on scroll
1333
+ window.elementPaddingChange = function(e) {
1334
+ gsap.to(e, {
1335
+ scrollTrigger: {
1336
+ trigger: e,
1337
+ start: 'top bottom',
1338
+ end: 'top top',
1339
+ toggleActions: 'restart none none reverse',
1340
+ scrub: 1,
1341
+ },
1342
+ paddingLeft: '0rem',
1343
+ paddingRight: '0rem',
1344
+ ease: 'linear',
1345
+ });
1346
+ }
1347
+
1348
+ // Section bg change
1349
+ window.sectionBgChange = function(e) {
1350
+ gsap.set(e, { backgroundColor: '#fff' });
1351
+ gsap.set('#heroNavbarLottie path', { fill: 'rgb(21, 21, 21)' });
1352
+ const sectionsBgChange = gsap.timeline({
1353
+ duration: 0.15,
1354
+ ease: 'loader2',
1355
+ scrollTrigger: {
1356
+ trigger: e,
1357
+ start: 'top center',
1358
+ end: 'bottom top',
1359
+ toggleActions: 'play reverse play reverse',
1360
+ },
1361
+ });
1362
+ sectionsBgChange.to(['#skills', '#portfolio'], {
1363
+ backgroundColor: '#151515',
1364
+ }, '<');
1365
+ sectionsBgChange.to(".info-bar_wrapper", {
1366
+ backgroundColor: '#2E2E2E',
1367
+ color: "#fff"
1368
+ }, '<');
1369
+ // Change navbar element on bg animation
1370
+ sectionsBgChange.to(
1371
+ [
1372
+ '.button_small',
1373
+ '.button_small_icon',
1374
+ '.navbar_brand_svg',
1375
+ '#heroNavbarLottie path ',
1376
+ ],
1377
+ {
1378
+ color: '#fff',
1379
+ fill: 'rgb(254, 254, 254)',
1380
+ },
1381
+ '<'
1382
+ );
1383
+ if (window.innerWidth > 992) {
1384
+ sectionsBgChange.to(
1385
+ '.navbar_menu_link',
1386
+ {
1387
+ color: '#fff',
1388
+ fill: 'rgb(254, 254, 254)',
1201
1389
  },
1202
- paddingLeft: '0rem',
1203
- paddingRight: '0rem',
1204
- ease: 'linear',
1205
- });
1390
+ '<'
1391
+ );
1206
1392
  }
1207
-
1208
- // Section bg change
1209
- window.sectionBgChange = function(e) {
1210
- gsap.set(e, { backgroundColor: '#fff' });
1211
- gsap.set('#heroNavbarLottie path', { fill: 'rgb(21, 21, 21)' });
1212
- const sectionsBgChange = gsap.timeline({
1213
- duration: 0.15,
1214
- ease: 'loader2',
1215
- scrollTrigger: {
1216
- trigger: e,
1217
- start: 'top center',
1218
- end: 'bottom top',
1219
- toggleActions: 'play reverse play reverse',
1220
- },
1221
- });
1222
- sectionsBgChange.to(['#skills', '#portfolio'], {
1223
- backgroundColor: '#151515',
1224
- }, '<');
1225
- sectionsBgChange.to(".info-bar_wrapper", {
1226
- backgroundColor: '#2E2E2E',
1227
- color: "#fff"
1228
- }, '<');
1229
- // Change navbar element on bg animation
1230
- sectionsBgChange.to(
1231
- [
1232
- '.button_small',
1233
- '.button_small_icon',
1234
- '.navbar_brand_svg',
1235
- '#heroNavbarLottie path ',
1236
- ],
1237
- {
1238
- color: '#fff',
1239
- fill: 'rgb(254, 254, 254)',
1240
- },
1241
- '<'
1242
- );
1243
- if (window.innerWidth > 992) {
1244
- sectionsBgChange.to(
1245
- '.navbar_menu_link',
1246
- {
1247
- color: '#fff',
1248
- fill: 'rgb(254, 254, 254)',
1249
- },
1250
- '<'
1251
- );
1252
- }
1253
- }
1393
+ }
1254
1394
 
1255
1395
  // Awwwards badge color change
1256
1396
  window.badgeColorChange = function(e) {
@@ -1272,262 +1412,261 @@ window.badgeColorChange = function(e) {
1272
1412
  }, '<');
1273
1413
  }
1274
1414
 
1275
- // Client logos animation
1276
- window.clientLogosAnimation = function(e) {
1277
- const logosStagger = 0.15;
1278
- const logoMask = e.querySelectorAll('[class*="item_mask"]');
1279
- const logoImg = e.querySelectorAll('[class*="image"]');
1280
- gsap.from(logoMask, {
1281
- scrollTrigger: {
1282
- trigger: logoMask,
1283
- start: 'top bottom-=25%',
1284
- },
1285
- width: '0%',
1286
- duration: 0.7,
1287
- ease: 'loader2',
1288
- stagger: logosStagger,
1415
+ // Client logos animation
1416
+ window.clientLogosAnimation = function(e) {
1417
+ const logosStagger = 0.15;
1418
+ const logoMask = e.querySelectorAll('[class*="item_mask"]');
1419
+ const logoImg = e.querySelectorAll('[class*="image"]');
1420
+ gsap.from(logoMask, {
1421
+ scrollTrigger: {
1422
+ trigger: logoMask,
1423
+ start: 'top bottom-=25%',
1424
+ },
1425
+ width: '0%',
1426
+ duration: 0.7,
1427
+ ease: 'loader2',
1428
+ stagger: logosStagger,
1429
+ });
1430
+ gsap.from(logoImg, {
1431
+ scrollTrigger: {
1432
+ trigger: logoMask,
1433
+ start: 'top bottom-=25%',
1434
+ },
1435
+ opacity: 0,
1436
+ delay: 0.4,
1437
+ duration: 0.45,
1438
+ ease: 'loader2',
1439
+ stagger: logosStagger,
1440
+ });
1441
+ }
1442
+
1443
+ // Hero span video on hover
1444
+ window.heroSpanVideoOnHover = function(e) {
1445
+ window.customCursorText(e);
1446
+ const heroSpanContentAnimation = gsap.timeline({ paused: true, ease: 'loader2' });
1447
+ heroSpanContentAnimation.to('.hero-line-mask', { clipPath: 'none', duration: 0.05 }, '>');
1448
+ heroSpanContentAnimation.to(e, { scale: 2, duration: 0.35 }, '>');
1449
+ if (window.innerWidth > 992) {
1450
+ e.addEventListener('mouseenter', () => {
1451
+ heroSpanContentAnimation.timeScale(1).play();
1289
1452
  });
1290
- gsap.from(logoImg, {
1291
- scrollTrigger: {
1292
- trigger: logoMask,
1293
- start: 'top bottom-=25%',
1294
- },
1295
- opacity: 0,
1296
- delay: 0.4,
1297
- duration: 0.45,
1298
- ease: 'loader2',
1299
- stagger: logosStagger,
1453
+ e.addEventListener('mouseleave', () => {
1454
+ heroSpanContentAnimation.timeScale(2).reverse();
1300
1455
  });
1301
1456
  }
1457
+ }
1302
1458
 
1303
- // Hero span video on hover
1304
- window.heroSpanVideoOnHover = function(e) {
1305
- window.customCursorText(e);
1306
- const heroSpanContentAnimation = gsap.timeline({ paused: true, ease: 'loader2' });
1307
- heroSpanContentAnimation.to('.hero-line-mask', { clipPath: 'none', duration: 0.05 }, '>');
1308
- heroSpanContentAnimation.to(e, { scale: 2, duration: 0.35 }, '>');
1309
- if (window.innerWidth > 992) {
1310
- e.addEventListener('mouseenter', () => {
1311
- heroSpanContentAnimation.timeScale(1).play();
1312
- });
1313
- e.addEventListener('mouseleave', () => {
1314
- heroSpanContentAnimation.timeScale(2).reverse();
1315
- });
1459
+ // Reel modal
1460
+ window.reelModal = function() {
1461
+ const reelTrigger = document.querySelectorAll('[wideClick="playReel"]');
1462
+ const reelModal = document.querySelector('.reel-modal');
1463
+ const reelModalPlayer = document.getElementById('fullReel');
1464
+ const reelPlayback = 0;
1465
+ const reelModalShow = gsap.timeline({ ease: 'loader2', paused: true });
1466
+ reelModalShow.to(reelModal, { display: 'flex', opacity: 0, duration: 0 });
1467
+ reelModalShow.to(reelModal, { opacity: 1, duration: 0.6 }, '>');
1468
+ if (window.innerWidth > 992) {
1469
+ reelTrigger.forEach((element) => {
1470
+ element.addEventListener('click', () => {
1471
+ lenis.stop();
1472
+ reelModalShow.timeScale(1).play();
1473
+ // Set the video source based on whether the player can handle WebM
1474
+ if (reelPlayback === 0) {
1475
+ if (reelModalPlayer.canPlayType('video/webm')) {
1476
+ reelModalPlayer.src =
1477
+ 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.webm';
1478
+ } else {
1479
+ reelModalPlayer.src =
1480
+ 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.mp4';
1481
+ }
1482
+ // Load the video
1483
+ reelModalPlayer.load();
1484
+ } else {
1485
+ return;
1486
+ }
1487
+
1488
+ reelModalPlayer.play();
1489
+ });
1490
+ });
1491
+ reelModal.addEventListener('click', () => {
1492
+ reelModalShow.timeScale(4).reverse();
1493
+ reelModalPlayer.pause();
1494
+ lenis.start();
1495
+ });
1496
+ window.addEventListener('keydown', function (event) {
1497
+ // The key code for the ESC key is 27
1498
+ if (event.keyCode === 27) {
1499
+ reelModalShow.timeScale(4).reverse();
1500
+ reelModalPlayer.pause();
1501
+ lenis.start();
1316
1502
  }
1317
- }
1503
+ });
1504
+ } else {
1505
+ reelTrigger.forEach((element) => {
1506
+ element.addEventListener('click', () => {
1507
+ // Set the video source based on whether the player can handle WebM
1508
+ if (reelModalPlayer.canPlayType('video/webm')) {
1509
+ reelModalPlayer.src = 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.webm';
1510
+ } else {
1511
+ reelModalPlayer.src = 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.mp4';
1512
+ }
1318
1513
 
1319
- // Reel modal
1320
- window.reelModal = function() {
1321
- const reelTrigger = document.querySelectorAll('[wideClick="playReel"]');
1322
- const reelModal = document.querySelector('.reel-modal');
1323
- const reelModalPlayer = document.getElementById('fullReel');
1324
- const reelPlayback = 0;
1325
- const reelModalShow = gsap.timeline({ ease: 'loader2', paused: true });
1326
- reelModalShow.to(reelModal, { display: 'flex', opacity: 0, duration: 0 });
1327
- reelModalShow.to(reelModal, { opacity: 1, duration: 0.6 }, '>');
1328
- if (window.innerWidth > 992) {
1329
- reelTrigger.forEach((element) => {
1330
- element.addEventListener('click', () => {
1331
- lenis.stop();
1332
- reelModalShow.timeScale(1).play();
1333
- // Set the video source based on whether the player can handle WebM
1334
- if (reelPlayback === 0) {
1335
- if (reelModalPlayer.canPlayType('video/webm')) {
1336
- reelModalPlayer.src =
1337
- 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.webm';
1338
- } else {
1339
- reelModalPlayer.src =
1340
- 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.mp4';
1341
- }
1342
- // Load the video
1343
- reelModalPlayer.load();
1344
- } else {
1345
- return;
1346
- }
1514
+ // Load the video
1515
+ reelModalPlayer.load();
1347
1516
 
1517
+ // Add a listener to the 'canplaythrough' event
1518
+ reelModalPlayer.addEventListener(
1519
+ 'canplaythrough',
1520
+ () => {
1521
+ // Once there's enough data loaded to play through, start playback
1348
1522
  reelModalPlayer.play();
1349
- });
1350
- });
1351
- reelModal.addEventListener('click', () => {
1352
- reelModalShow.timeScale(4).reverse();
1353
- reelModalPlayer.pause();
1354
- lenis.start();
1355
- });
1356
- window.addEventListener('keydown', function (event) {
1357
- // The key code for the ESC key is 27
1358
- if (event.keyCode === 27) {
1359
- reelModalShow.timeScale(4).reverse();
1360
- reelModalPlayer.pause();
1361
- lenis.start();
1362
- }
1363
- });
1364
- } else {
1365
- reelTrigger.forEach((element) => {
1366
- element.addEventListener('click', () => {
1367
- // Set the video source based on whether the player can handle WebM
1368
- if (reelModalPlayer.canPlayType('video/webm')) {
1369
- reelModalPlayer.src = 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.webm';
1370
- } else {
1371
- reelModalPlayer.src = 'https://widelabco.sfo3.cdn.digitaloceanspaces.com/Widelab-reel.mp4';
1372
- }
1373
-
1374
- // Load the video
1375
- reelModalPlayer.load();
1376
-
1377
- // Add a listener to the 'canplaythrough' event
1378
- reelModalPlayer.addEventListener(
1379
- 'canplaythrough',
1380
- () => {
1381
- // Once there's enough data loaded to play through, start playback
1382
- reelModalPlayer.play();
1383
- },
1384
- { once: true }
1385
- ); // Ensure this event only fires once per click
1386
- });
1387
- });
1388
- reelModal.addEventListener('click', () => {
1389
- reelModalPlayer.pause();
1390
- });
1391
- }
1523
+ },
1524
+ { once: true }
1525
+ ); // Ensure this event only fires once per click
1526
+ });
1527
+ });
1528
+ reelModal.addEventListener('click', () => {
1529
+ reelModalPlayer.pause();
1530
+ });
1392
1531
  }
1532
+ }
1393
1533
 
1394
- // Founders tooltip
1395
- window.foundersTooltip = function(e) {
1396
- const line = e.querySelector('.line');
1397
- const arrow = e.querySelector('.arrow');
1398
- const foundersHover = gsap.timeline({ paused: true, ease: 'loader2' });
1399
- foundersHover.from(e, {
1400
- x: '5%',
1401
- opacity: 0,
1402
- duration: 0.4,
1403
- });
1404
- foundersHover.from(
1405
- line,
1406
- {
1407
- drawSVG: '0% 0%',
1408
- duration: 0.2,
1409
- },
1410
- '>-0.2'
1411
- );
1412
- foundersHover.from(arrow, {
1534
+ // Founders tooltip
1535
+ window.foundersTooltip = function(e) {
1536
+ const line = e.querySelector('.line');
1537
+ const arrow = e.querySelector('.arrow');
1538
+ const foundersHover = gsap.timeline({ paused: true, ease: 'loader2' });
1539
+ foundersHover.from(e, {
1540
+ x: '5%',
1541
+ opacity: 0,
1542
+ duration: 0.4,
1543
+ });
1544
+ foundersHover.from(
1545
+ line,
1546
+ {
1413
1547
  drawSVG: '0% 0%',
1414
- duration: 0.15,
1415
- }),
1416
- '>';
1417
- if (window.innerWidth > 992) {
1418
- e.addEventListener('mouseenter', () => {
1419
- foundersHover.timeScale(1).play();
1420
- });
1421
- e.addEventListener('mouseleave', () => {
1422
- foundersHover.timeScale(3).reverse();
1423
- });
1424
- }
1548
+ duration: 0.2,
1549
+ },
1550
+ '>-0.2'
1551
+ );
1552
+ foundersHover.from(arrow, {
1553
+ drawSVG: '0% 0%',
1554
+ duration: 0.15,
1555
+ }),
1556
+ '>';
1557
+ if (window.innerWidth > 992) {
1558
+ e.addEventListener('mouseenter', () => {
1559
+ foundersHover.timeScale(1).play();
1560
+ });
1561
+ e.addEventListener('mouseleave', () => {
1562
+ foundersHover.timeScale(3).reverse();
1563
+ });
1425
1564
  }
1565
+ }
1426
1566
 
1427
- // Clients map actions
1428
- window.clientsMapActions = function(e) {
1429
- // Map animation
1430
- const mapAnimation = gsap.timeline({
1431
- scrollTrigger: {
1432
- trigger: '.reviews_map_base',
1433
- start: 'bottom-=160px bottom',
1434
- },
1435
- });
1436
- mapAnimation.from('.map-point', {
1567
+ // Clients map actions
1568
+ window.clientsMapActions = function(e) {
1569
+ // Map animation
1570
+ const mapAnimation = gsap.timeline({
1571
+ scrollTrigger: {
1572
+ trigger: '.reviews_map_base',
1573
+ start: 'bottom-=160px bottom',
1574
+ },
1575
+ });
1576
+ mapAnimation.from('.map-point', {
1577
+ duration: 1,
1578
+ opacity: 0,
1579
+ stagger: 0.1,
1580
+ ease: 'loader2',
1581
+ });
1582
+ mapAnimation.from(
1583
+ '.map-pin_wrapper',
1584
+ {
1437
1585
  duration: 1,
1438
1586
  opacity: 0,
1439
1587
  stagger: 0.1,
1440
1588
  ease: 'loader2',
1441
- });
1442
- mapAnimation.from(
1443
- '.map-pin_wrapper',
1444
- {
1445
- duration: 1,
1589
+ },
1590
+ '0.3'
1591
+ );
1592
+
1593
+ // Map pins animation on hover
1594
+ const allMapPins = document.querySelectorAll('.map-pin_wrapper');
1595
+ allMapPins.forEach(function (element) {
1596
+ element.addEventListener('mouseenter', function () {
1597
+ const mapPin = this.getAttribute('w-map-pin');
1598
+ const oldPin = document.querySelectorAll('.map_info-collection-item');
1599
+ const infoElements = document.querySelectorAll(
1600
+ ".map_info-collection-item[w-map-info='" + mapPin + "']"
1601
+ );
1602
+ const infoElementsAppear = gsap.timeline({});
1603
+ infoElementsAppear.to(oldPin, {
1446
1604
  opacity: 0,
1447
- stagger: 0.1,
1448
1605
  ease: 'loader2',
1449
- },
1450
- '0.3'
1451
- );
1452
-
1453
- // Map pins animation on hover
1454
- const allMapPins = document.querySelectorAll('.map-pin_wrapper');
1455
- allMapPins.forEach(function (element) {
1456
- element.addEventListener('mouseenter', function () {
1457
- const mapPin = this.getAttribute('w-map-pin');
1458
- const oldPin = document.querySelectorAll('.map_info-collection-item');
1459
- const infoElements = document.querySelectorAll(
1460
- ".map_info-collection-item[w-map-info='" + mapPin + "']"
1461
- );
1462
- const infoElementsAppear = gsap.timeline({});
1463
- infoElementsAppear.to(oldPin, {
1464
- opacity: 0,
1465
- ease: 'loader2',
1466
- duration: 0.1,
1467
- });
1468
- infoElementsAppear.to(oldPin, {
1469
- display: 'none',
1470
- duration: 0.01,
1471
- });
1472
- infoElementsAppear.to(infoElements, {
1473
- display: 'block',
1474
- duration: 0.01,
1475
- });
1476
- infoElementsAppear.to(infoElements, {
1477
- opacity: 1,
1478
- ease: 'loader2',
1479
- duration: 0.2,
1480
- });
1606
+ duration: 0.1,
1607
+ });
1608
+ infoElementsAppear.to(oldPin, {
1609
+ display: 'none',
1610
+ duration: 0.01,
1611
+ });
1612
+ infoElementsAppear.to(infoElements, {
1613
+ display: 'block',
1614
+ duration: 0.01,
1615
+ });
1616
+ infoElementsAppear.to(infoElements, {
1617
+ opacity: 1,
1618
+ ease: 'loader2',
1619
+ duration: 0.2,
1481
1620
  });
1482
1621
  });
1483
- // Map boxes link special code
1484
- const elements = document.querySelectorAll('.map_info-wrapper');
1485
- for (let i = 0; i < elements.length; i++) {
1486
- const href = elements[i].getAttribute('href');
1487
- if (href && href.length > 3) {
1488
- elements[i].style.cursor = 'pointer';
1489
- }
1490
- }
1622
+ });
1623
+ // Map boxes link special code
1624
+ const elements = document.querySelectorAll('.map_info-wrapper');
1625
+ for (let i = 0; i < elements.length; i++) {
1626
+ const href = elements[i].getAttribute('href');
1627
+ if (href && href.length > 3) {
1628
+ elements[i].style.cursor = 'pointer';
1629
+ }
1491
1630
  }
1631
+ }
1492
1632
 
1493
1633
 
1494
-
1495
- // Stats section headline animation
1496
- window.statsHeadlineAnimation = function() {
1497
- const statsHeadlineAnimation = gsap.timeline({
1498
- scrollTrigger: {
1499
- trigger: '#statsKnow',
1500
- start: 'center center',
1501
- toggleActions: 'restart none none reverse',
1502
- end: '+=500',
1503
- },
1504
- pause: 'paused',
1505
- ease: 'defaultEase',
1506
- }),
1507
- homeStatsHeading = new SplitText('#statsDone', {
1508
- type: 'lines',
1509
- linesClass: 'stats-line',
1510
- }),
1511
- homeStatsHeadingMask = new SplitText('#statsDone', {
1512
- type: 'lines',
1513
- linesClass: 'stats-line-mask',
1514
- });
1515
- statsHeadlineAnimation.to(
1516
- '#statsKnow',
1517
- {
1518
- duration: 0.5,
1519
- opacity: 0,
1520
- display: 'none',
1634
+ // Stats section headline animation
1635
+ window.statsHeadlineAnimation = function() {
1636
+ const statsHeadlineAnimation = gsap.timeline({
1637
+ scrollTrigger: {
1638
+ trigger: '#statsKnow',
1639
+ start: 'center center',
1640
+ toggleActions: 'restart none none reverse',
1641
+ end: '+=500',
1521
1642
  },
1522
- '>'
1523
- );
1524
- statsHeadlineAnimation.from('.stats-line', {
1643
+ pause: 'paused',
1644
+ ease: 'defaultEase',
1645
+ }),
1646
+ homeStatsHeading = new SplitText('#statsDone', {
1647
+ type: 'lines',
1648
+ linesClass: 'stats-line',
1649
+ }),
1650
+ homeStatsHeadingMask = new SplitText('#statsDone', {
1651
+ type: 'lines',
1652
+ linesClass: 'stats-line-mask',
1653
+ });
1654
+ statsHeadlineAnimation.to(
1655
+ '#statsKnow',
1656
+ {
1525
1657
  duration: 0.5,
1526
1658
  opacity: 0,
1527
- y: '100%',
1528
- stagger: 0.25,
1529
- });
1530
- }
1659
+ display: 'none',
1660
+ },
1661
+ '>'
1662
+ );
1663
+ statsHeadlineAnimation.from('.stats-line', {
1664
+ duration: 0.5,
1665
+ opacity: 0,
1666
+ y: '100%',
1667
+ stagger: 0.25,
1668
+ });
1669
+ }
1531
1670
 
1532
1671
  // Single entry you call from x-init
1533
1672
  window.clientFilters = function () {
@@ -2151,7 +2290,7 @@ window.initBentoRevealScrub = function (container) {
2151
2290
  start: 'top 90%', // start easing in slightly later
2152
2291
  end: 'bottom 65%', // full reveal by near the end of container
2153
2292
  scrub: 0.5, // smoothing; use true for no smoothing
2154
- markers: false, // uncomment for debugging
2293
+ markers: false, // uncomment for debugging
2155
2294
  }
2156
2295
  });
2157
2296
 
@@ -2253,101 +2392,101 @@ window.initPartnerVideos = function (container) {
2253
2392
  };
2254
2393
 
2255
2394
 
2256
- // Case study - What's next interaction
2257
- window.whatsNext = function() {
2258
- const caseItem = document.querySelectorAll('.whats-next_links_item.is-case');
2259
- const allCases = document.querySelector('.whats-next_links_item.is-all');
2260
- caseItem.forEach((item) => {
2261
- const imageMask = item.querySelector('.whats-next_links_item_image_mask');
2262
- const imageWrapper = item.querySelector('.whats-next_links_item_image-wrapper');
2263
- const whatsNextHover = gsap.timeline({ paused: true, ease: 'loader2' });
2264
- whatsNextHover.to(imageWrapper, { opacity: 0.8, duration: 0.15 });
2265
- whatsNextHover.to(imageMask, { width: '0%', duration: 0.3 }, '>-0.');
2266
- item.addEventListener('mouseenter', () => {
2267
- whatsNextHover.timeScale(1).play();
2268
- caseItem.forEach((i) => {
2269
- if (i !== event.target) {
2270
- gsap.to(i, { color: '#7A7A7A', duration: 0.2, ease: 'loader2' });
2271
- }
2272
- });
2273
- });
2274
- item.addEventListener('mouseleave', () => {
2275
- whatsNextHover.timeScale(3).reverse();
2276
- caseItem.forEach((i) => {
2277
- if (i !== event.target) {
2278
- gsap.to(i, { color: '#fff', duration: 0.1, ease: 'loader2' });
2279
- }
2280
- });
2395
+ // Case study - What's next interaction
2396
+ window.whatsNext = function() {
2397
+ const caseItem = document.querySelectorAll('.whats-next_links_item.is-case');
2398
+ const allCases = document.querySelector('.whats-next_links_item.is-all');
2399
+ caseItem.forEach((item) => {
2400
+ const imageMask = item.querySelector('.whats-next_links_item_image_mask');
2401
+ const imageWrapper = item.querySelector('.whats-next_links_item_image-wrapper');
2402
+ const whatsNextHover = gsap.timeline({ paused: true, ease: 'loader2' });
2403
+ whatsNextHover.to(imageWrapper, { opacity: 0.8, duration: 0.15 });
2404
+ whatsNextHover.to(imageMask, { width: '0%', duration: 0.3 }, '>-0.');
2405
+ item.addEventListener('mouseenter', () => {
2406
+ whatsNextHover.timeScale(1).play();
2407
+ caseItem.forEach((i) => {
2408
+ if (i !== event.target) {
2409
+ gsap.to(i, { color: '#7A7A7A', duration: 0.2, ease: 'loader2' });
2410
+ }
2281
2411
  });
2282
2412
  });
2283
- allCases.addEventListener('mouseenter', () => {
2284
- gsap.to(allCases, { color: '#fff', duration: 0.2, ease: 'loader2' });
2285
- caseItem.forEach((item) => {
2286
- gsap.to(item, { color: '#7A7A7A', duration: 0.2, ease: 'loader2' });
2413
+ item.addEventListener('mouseleave', () => {
2414
+ whatsNextHover.timeScale(3).reverse();
2415
+ caseItem.forEach((i) => {
2416
+ if (i !== event.target) {
2417
+ gsap.to(i, { color: '#fff', duration: 0.1, ease: 'loader2' });
2418
+ }
2287
2419
  });
2288
2420
  });
2289
- allCases.addEventListener('mouseleave', () => {
2290
- gsap.to(allCases, { color: '#7A7A7A', duration: 0.2, ease: 'loader2' });
2291
- caseItem.forEach((item) => {
2292
- gsap.to(item, { color: '#fff', duration: 0.2, ease: 'loader2' });
2293
- });
2421
+ });
2422
+ allCases.addEventListener('mouseenter', () => {
2423
+ gsap.to(allCases, { color: '#fff', duration: 0.2, ease: 'loader2' });
2424
+ caseItem.forEach((item) => {
2425
+ gsap.to(item, { color: '#7A7A7A', duration: 0.2, ease: 'loader2' });
2294
2426
  });
2427
+ });
2428
+ allCases.addEventListener('mouseleave', () => {
2429
+ gsap.to(allCases, { color: '#7A7A7A', duration: 0.2, ease: 'loader2' });
2430
+ caseItem.forEach((item) => {
2431
+ gsap.to(item, { color: '#fff', duration: 0.2, ease: 'loader2' });
2432
+ });
2433
+ });
2295
2434
 
2296
- // Remove responsive image feature from CS pages
2297
- for (var i = 0; i < document.getElementsByTagName('img').length; i++) {
2298
- document.getElementsByTagName('img')[i].srcset = '';
2299
- }
2300
- for (var i = 0; i < document.getElementsByTagName('img').length; i++) {
2301
- document.getElementsByTagName('img')[i].sizes = '';
2302
- }
2435
+ // Remove responsive image feature from CS pages
2436
+ for (var i = 0; i < document.getElementsByTagName('img').length; i++) {
2437
+ document.getElementsByTagName('img')[i].srcset = '';
2303
2438
  }
2439
+ for (var i = 0; i < document.getElementsByTagName('img').length; i++) {
2440
+ document.getElementsByTagName('img')[i].sizes = '';
2441
+ }
2442
+ }
2304
2443
 
2305
- // Case study - images mask animation
2306
- window.csMaskAnimation = function() {
2307
- const csImageMasks = document.querySelectorAll('.portfolio_item_image-mask');
2308
- csImageMasks.forEach((mask, index) => {
2309
- if (index === 0) {
2310
- return;
2311
- }
2312
- const maskAnimation = gsap.from(mask, {
2313
- width: '100%',
2314
- duration: 0.7,
2315
- ease: 'loader2',
2316
- paused: true,
2317
- });
2318
- ScrollTrigger.create({
2319
- animation: maskAnimation,
2320
- trigger: mask,
2321
- start: 'top 80%',
2322
- onEnter: () => maskAnimation.play(),
2323
- });
2444
+ // Case study - images mask animation
2445
+ window.csMaskAnimation = function() {
2446
+ const csImageMasks = document.querySelectorAll('.portfolio_item_image-mask');
2447
+ csImageMasks.forEach((mask, index) => {
2448
+ if (index === 0) {
2449
+ return;
2450
+ }
2451
+ const maskAnimation = gsap.from(mask, {
2452
+ width: '100%',
2453
+ duration: 0.7,
2454
+ ease: 'loader2',
2455
+ paused: true,
2324
2456
  });
2325
- }
2457
+ ScrollTrigger.create({
2458
+ animation: maskAnimation,
2459
+ trigger: mask,
2460
+ start: 'top 80%',
2461
+ onEnter: () => maskAnimation.play(),
2462
+ });
2463
+ });
2464
+ }
2326
2465
 
2327
- // Update the scroll trigger on page load
2466
+ // Update the scroll trigger on page load
2328
2467
  window.updateScrollTrigger = function() {
2329
2468
  window.onload = function() {
2330
2469
  ScrollTrigger.update();
2331
2470
  };
2332
2471
  }
2333
2472
 
2334
- // Blog post main image mask animation
2335
- window.blogPostMaskAnimation = function(e) {
2336
- const blogHero = document.querySelector('#heroSection');
2337
- const blogMaskAnimation = gsap.from('.post_main-mask-ract', {
2338
- left: '0%',
2339
- ease: 'loader2',
2340
- });
2341
- ScrollTrigger.create({
2342
- animation: blogMaskAnimation,
2343
- trigger: blogHero,
2344
- start: 'top -5%',
2345
- end: 'bottom 50%',
2346
- scrub: 0.5,
2347
- });
2348
- }
2473
+ // Blog post main image mask animation
2474
+ window.blogPostMaskAnimation = function(e) {
2475
+ const blogHero = document.querySelector('#heroSection');
2476
+ const blogMaskAnimation = gsap.from('.post_main-mask-ract', {
2477
+ left: '0%',
2478
+ ease: 'loader2',
2479
+ });
2480
+ ScrollTrigger.create({
2481
+ animation: blogMaskAnimation,
2482
+ trigger: blogHero,
2483
+ start: 'top -5%',
2484
+ end: 'bottom 50%',
2485
+ scrub: 0.5,
2486
+ });
2487
+ }
2349
2488
 
2350
- // Custom checkboxes
2489
+ // Custom checkboxes
2351
2490
  window.changeCheckboxLabelColor = function() {
2352
2491
  let checkboxInputs = document.querySelectorAll('.w-checkbox-input');
2353
2492
 
@@ -2372,7 +2511,7 @@ window.changeCheckboxLabelColor = function() {
2372
2511
  });
2373
2512
  }
2374
2513
 
2375
- // Contact modal open animation
2514
+ // Contact modal open animation
2376
2515
  window.openContactModal = function() {
2377
2516
  contactFormOpen.play();
2378
2517
  document.body.classList.add('is-scroll-off');
@@ -2417,15 +2556,15 @@ window.successMsgAnimation = function(e) {
2417
2556
  ease: 'loader2',
2418
2557
  }
2419
2558
  );
2420
- successMsgAnim.to(
2421
- e,
2422
- {
2423
- width: '0%',
2424
- duration: 0.6,
2425
- ease: 'loader2',
2426
- },
2427
- '>-0.5'
2428
- );
2559
+ successMsgAnim.to(
2560
+ e,
2561
+ {
2562
+ width: '0%',
2563
+ duration: 0.6,
2564
+ ease: 'loader2',
2565
+ },
2566
+ '>-0.5'
2567
+ );
2429
2568
  successMsgAnim.from(
2430
2569
  '#successParagraph',
2431
2570
  {
@@ -2472,7 +2611,6 @@ window.contactUsHide = function(e) {
2472
2611
  }
2473
2612
 
2474
2613
 
2475
-
2476
2614
  window.expandablePadSticky = function (e) {
2477
2615
  var wrapper = e;
2478
2616
  if (!wrapper || wrapper.dataset.expandablePadStickyInit === 'true') return;
@@ -2517,13 +2655,38 @@ window.expandablePadSticky = function (e) {
2517
2655
  }
2518
2656
  }
2519
2657
 
2658
+ // Click a tab (the title row next to .service_expanded) to scroll to its trigger point
2659
+ function scrollToIndex(index) {
2660
+ var rect = wrapper.getBoundingClientRect();
2661
+ var absoluteTop = rect.top + window.pageYOffset;
2662
+ var total = wrapper.offsetHeight - window.innerHeight;
2663
+ if (total <= 0) return;
2664
+ var progress = (index + 0.5) / (count + 1);
2665
+ var targetY = absoluteTop + progress * total;
2666
+
2667
+ lenis.scrollTo(targetY, {
2668
+ duration: 1.2,
2669
+ easing: function (t) { return Math.min(1, 1.001 - Math.pow(2, -10 * t)); },
2670
+ });
2671
+ }
2672
+
2673
+ for (var i = 0; i < items.length; i++) {
2674
+ (function (index) {
2675
+ var parent = items[index].parentElement;
2676
+ var tab = parent ? parent.querySelector('.service_item-wrapper.is-p-l') : null;
2677
+ if (!tab) return;
2678
+ tab.addEventListener('click', function () {
2679
+ scrollToIndex(index);
2680
+ });
2681
+ })(i);
2682
+ }
2683
+
2520
2684
  window.addEventListener('scroll', onScrollOrResize, { passive: true });
2521
2685
  window.addEventListener('resize', onResize);
2522
2686
  update();
2523
2687
  };
2524
2688
 
2525
2689
 
2526
-
2527
2690
  // Refresh Gsap scrollTriggers
2528
2691
  window.scrollTriggerRefresh = function() {
2529
2692
  function refreshScrollTrigger() {
@@ -2537,7 +2700,7 @@ window.scrollTriggerRefresh = function() {
2537
2700
 
2538
2701
  // Info bar close animation
2539
2702
  window.closeInfoBar = function() {
2540
- const infoBarClose = gsap.timeline({});
2703
+ const infoBarClose = gsap.timeline({});
2541
2704
  infoBarClose.to('.info-bar', {
2542
2705
  height: 0,
2543
2706
  autoAlpha: 0,
@@ -2558,31 +2721,29 @@ window.closeInfoBar = function() {
2558
2721
  }
2559
2722
 
2560
2723
 
2724
+ // !!!!!!!!! Keep this Alpine init at the end !!!!!!!!!
2725
+ window.Webflow ||= [];
2726
+ window.Webflow.push(() => {
2561
2727
 
2562
-
2563
- // !!!!!!!!! Keep this Alpine init at the end !!!!!!!!!
2564
- window.Webflow ||= [];
2565
- window.Webflow.push(() => {
2566
-
2567
- console.log('The new code source is loaded!');
2568
- initAlpine();
2569
- lazyLoadVideos();
2570
- if (Webflow.env("editor") === undefined) {
2571
- lenisScroll();
2572
- lenis.start();
2573
- } else {
2574
- console.log('Editor mode ON');
2575
- lenis.destroy();
2576
- }
2577
- customGsapEasing();
2578
- reloadOnBack();
2579
- revealFooter();
2580
- pageLoadAnimation();
2581
- pageTransitionAnimation();
2582
- customCursorOnClick();
2583
- contactFormOpenAnimation();
2584
- disableScrollMenu();
2585
- scrollToHashOnLoad();
2586
- initClientLogosAnimation();
2587
- articleModalOpenAnimation();
2588
- });
2728
+ console.log('The new code source is loaded!');
2729
+ initAlpine();
2730
+ lazyLoadVideos();
2731
+ if (Webflow.env("editor") === undefined) {
2732
+ lenisScroll();
2733
+ lenis.start();
2734
+ } else {
2735
+ console.log('Editor mode ON');
2736
+ lenis.destroy();
2737
+ }
2738
+ customGsapEasing();
2739
+ reloadOnBack();
2740
+ revealFooter();
2741
+ pageLoadAnimation();
2742
+ pageTransitionAnimation();
2743
+ customCursorOnClick();
2744
+ contactFormOpenAnimation();
2745
+ disableScrollMenu();
2746
+ scrollToHashOnLoad();
2747
+ initClientLogosAnimation();
2748
+ articleModalOpenAnimation();
2749
+ });