import '../src/style.css'; // import Swiper styles import 'swiper/css'; import 'swiper/css/effect-coverflow'; import 'swiper/css/navigation'; import 'swiper/css/a11y'; import 'swiper/css/autoplay'; import 'swiper/css/keyboard'; //import { WEBFLOW_BREAKPOINTS } from '@finsweet/ts-utils'; import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; import Lenis from 'lenis'; // Import Swiper and modules import Swiper from 'swiper'; import { A11y, Autoplay, Controller, EffectCoverflow, Keyboard, Navigation } from 'swiper/modules'; import type { SwiperOptions } from 'swiper/types'; gsap.registerPlugin(ScrollTrigger); // Ensure document is ready //document.addEventListener('DOMContentLoaded', () => { window.Webflow ||= []; window.Webflow.push(async () => { try { //#region Log State const shouldLog: boolean = false; function logMessage(...args: string[]): void { if (shouldLog) { /* eslint no-console: ["error", { allow: ["log", "error"] }] */ console.log(...args); } } function logErrorMessage(...args: string[]): void { if (shouldLog) { console.error(...args); } } logMessage("Document is ready, 'global.js' Loaded!"); //#endregion //#region LENIS SMOOTH SCROLL const lenis = new Lenis({ lerp: 0.1, wheelMultiplier: 1.3, infinite: false, gestureOrientation: 'vertical', }); lenis.on('scroll', ScrollTrigger.update); gsap.ticker.add((time) => { lenis.raf(time * 1000); }); gsap.ticker.lagSmoothing(0); //#endregion //#region Initialize Modal Close gsap.set('[Modal_Container]', { display: 'none' }); //#endregion function cleanupAnimationsForElements( elements: NodeListOf, animationType: 'scroll' | 'event' ) { elements.forEach((element) => { const card = element.querySelector('[how-card]'); if (card) { if (animationType === 'event') { card.replaceWith(card.cloneNode(true)); // Remove all event listeners by cloning } else if (animationType === 'scroll') { const scrollTriggerInstance = ScrollTrigger.getById(card.id); if (scrollTriggerInstance) { scrollTriggerInstance.kill(); // Kill only the specific ScrollTrigger instance } } } }); } function isSafari() { return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); } //#region Hero Scroll Animation // Debugging function function logProgress(progress: number): void { logMessage('Scroll progress msm:', progress.toString()); } function logBreakpoint(breakpoint: string): void { logMessage('Current breakpoint:', breakpoint); } function logBreakpointChange(breakpoint: string): void { logMessage('Breakpoint changed to:', breakpoint); } let currentBreakpoint: string = ''; const mm = gsap.matchMedia(); function updateTimeline(timeline: GSAPTimeline): void { timeline.invalidate(); ScrollTrigger.refresh(); } function createCtaAnimation(): void { gsap.set('[cta_wrapper]', { display: 'flex' }); const ctaWrapper = document.querySelector('[cta_wrapper]') as HTMLElement; const ctaTitleWrapper = document.querySelector('[cta-title_wrapper]') as HTMLElement; let ctaTitleWrapperHeight = ctaTitleWrapper.offsetHeight; interface Variables { translateY: string; offsetTop: number; textOpacity: number; buttonOpacity: number; buttonLeft: string; buttonWidth: string; buttonPadding: string; svgOpacity: number; backgroundImage: string; xPercent: number; } const ctaInitialValues: Variables = { translateY: '-50%', offsetTop: window.innerHeight * -0.1, textOpacity: 1, buttonOpacity: 1, buttonLeft: '0px', buttonWidth: '250px', buttonPadding: '30px', svgOpacity: 0, backgroundImage: 'linear-gradient(333deg, rgb(0, 65, 170), rgb(0, 98, 255)))', xPercent: 0, }; const ctaTargetValues: Variables = { translateY: '-50%', offsetTop: window.innerHeight * -0.1, textOpacity: 0, buttonOpacity: 0, buttonLeft: '50%', buttonWidth: '54px', buttonPadding: '0px', svgOpacity: 1, backgroundImage: 'linear-gradient(333deg, rgb(0, 97, 255), rgb(0, 237, 255))', xPercent: 0, }; const calculateTargetPosition = (): number => { return ctaWrapper.offsetHeight / 50 - window.innerHeight / 2 - ctaTitleWrapperHeight - 40; }; const updateTopPosition = (): void => { if (ctaTitleWrapper.offsetHeight !== ctaTitleWrapperHeight) { ctaTitleWrapperHeight = ctaTitleWrapper.offsetHeight; // Invalidate the timeline so it recalculates the values updateTimeline(ctaTimeline); } }; updateTopPosition(); const resizeObserver = new ResizeObserver(() => { updateTopPosition(); }); resizeObserver.observe(ctaTitleWrapper); const ctaTimeline = gsap.timeline({ scrollTrigger: { trigger: '.sticky_track', start: `top-=${ctaTargetValues.offsetTop} top`, end: `80% bottom`, scrub: true, onUpdate: (self) => logProgress(self.progress), }, }); ctaTimeline .fromTo( '[cta_text]', { opacity: ctaInitialValues.textOpacity }, { opacity: ctaTargetValues.textOpacity, stagger: 0.1, duration: 0.1 }, 0 ) .fromTo( '[cta-button_text]', { opacity: ctaInitialValues.buttonOpacity }, { opacity: ctaTargetValues.buttonOpacity, duration: 0.1 }, 0 ) .fromTo( '[cta_button]', { left: ctaInitialValues.buttonLeft, xPercent: ctaInitialValues.xPercent, width: ctaInitialValues.buttonWidth, paddingLeft: ctaInitialValues.buttonPadding, backgroundImage: ctaInitialValues.backgroundImage, }, { left: ctaTargetValues.buttonLeft, xPercent: -50, width: ctaTargetValues.buttonWidth, paddingLeft: ctaTargetValues.buttonPadding, backgroundImage: ctaTargetValues.backgroundImage, ease: 'power1.out', }, 0 ) .fromTo( '[cta_wrapper]', { translateY: ctaInitialValues.translateY, }, { translateY: () => calculateTargetPosition(), // Dynamically calculate target position }, 0 ) .fromTo( '.whatsapp_svg', { opacity: ctaInitialValues.svgOpacity }, { opacity: ctaTargetValues.svgOpacity }, 0.2 ); } function createHeroAnimations(): void { const heroTimeline = gsap.timeline({ scrollTrigger: { trigger: '.sticky_track', start: `top-=${window.innerHeight * -0.1} top`, end: `bottom-=${window.innerHeight * 0.2} bottom`, scrub: true, onUpdate: (self) => logProgress(self.progress), }, }); mm.add('(min-width: 992px)', () => { heroTimeline .fromTo( '.hero-wrapper', { width: '100%', maxWidth: '100%', height: '100%', backgroundColor: '#050505cc', }, { width: '90%', maxWidth: '1440px', height: 'calc(100dvh - 10rem)', backgroundColor: '#05050500', }, 0 ) .fromTo( '[hero-title-a_wrapper]', { width: 'calc(100% - 100px)', height: '100%', }, { width: '1296px', height: 'calc(100dvh - 10rem)', }, 0 ) .fromTo('[navbar]', { translateY: 0 }, { translateY: -80 }, 0) .fromTo( '.scrolldown_link', { opacity: 1, duration: 0.3 }, { opacity: 0, duration: 0.3 }, 0 ) .fromTo('.scrolldown_link', { y: 0 }, { y: '-10rem' }, 0) .fromTo('.herotitle-b_wrapper', { y: 0 }, { y: '-10rem' }, 0) .fromTo('.herotitle-a', { y: 0 }, { y: '-20rem' }, 0.05) .fromTo('.herotitle-b', { y: '-7rem', duration: 0.2 }, { y: 0, duration: 0.2 }, 0.2); }); mm.add('(max-width: 991px)', () => { heroTimeline .fromTo( '.hero-wrapper', { height: '100%', backgroundColor: '#050505cc', }, { height: 'calc(100dvh - 7rem)', backgroundColor: '#05050500', }, 0 ) .fromTo( '[hero-title-a_wrapper]', { height: '100%', }, { height: 'calc(100dvh - 7rem)', }, 0 ) .fromTo('[navbar]', { translateY: 0 }, { translateY: -80 }, 0) .fromTo( '.scrolldown_link', { opacity: 1, duration: 0.3 }, { opacity: 0, duration: 0.3 }, 0 ) .fromTo('.scrolldown_link', { y: 0 }, { y: '-7rem' }, 0) .fromTo('.herotitle-b_wrapper', { y: 0 }, { y: '-7rem' }, 0) .fromTo('.herotitle-a', { y: 0 }, { y: '-10.5rem' }, 0.05) .fromTo('.herotitle-b', { y: '-7rem', duration: 0.2 }, { y: 0, duration: 0.2 }, 0.2); }); } createHeroAnimations(); //#region Structure Letters Animation function createStructureLettersAnimation(): void { const structureLetters = document.querySelectorAll('[structure-letter]'); function shockwaveActivate(x: number, y: number): void { const shockwave = document.querySelector('[shockwave_structure]') as HTMLElement; if (shockwave) { // Set the initial position of the shockwave gsap.set(shockwave, { left: `${x}px`, top: `${y}px`, width: '0vw', height: '0vw', opacity: 0, }); // Animate the shockwave gsap.to(shockwave, { width: '40vw', height: '40vw', opacity: 0.5, duration: 0.5, // ease: 'power1.out', onComplete: () => { gsap.to(shockwave, { opacity: 0, duration: 0.1, onComplete: () => { gsap.set(shockwave, { width: 0, height: 0 }); }, }); }, }); gsap.to(shockwave, { opacity: 0, duration: 0.5, delay: 0.1, }); } } function hideStructureInfo(letterFilter: string): void { const targets = document.querySelectorAll( `[before-title_text="${letterFilter}"], [h3="${letterFilter}"], [learn-more_button="${letterFilter}"], [card="${letterFilter}"]` ); gsap.to(targets, { opacity: 0 }); gsap.to(`[card-content="${letterFilter}"]`, { background: 'transparent', }); gsap.to(`[card-border="${letterFilter}"]`, { opacity: 0 }); } function initializeTextStructureHided(): void { const targets = document.querySelectorAll( `[before-title_text], [h3], [learn-more_button], [card]` ); gsap.set(targets, { opacity: 0 }); gsap.set(`[card=""]`, { opacity: 1 }); gsap.set('[card-content]', { background: 'transparent' }); gsap.set('[card-border]', { opacity: 0 }); } initializeTextStructureHided(); function revealStructureInfo(letterFilter: string): void { const targets = document.querySelectorAll( `[before-title_text="${letterFilter}"], [h3="${letterFilter}"], [learn-more_button="${letterFilter}"], [card="${letterFilter}"]` ); gsap.to(targets, { opacity: 1, duration: 1 }); gsap.to(`[card-content="${letterFilter}"]`, { background: 'var(--secondary)', duration: 1, }); } function borderLightUp(letterFilter: string): void { const targets = document.querySelectorAll(`[card-border="${letterFilter}"]`); gsap.set(targets, { backgroundColor: '#ffffff99', backgroundImage: 'none' }); gsap.to(targets, { opacity: 1, duration: 0.2, ease: 'power1.in', onComplete: function () { gsap.to(targets, { duration: 0.5, ease: 'power1.out', backgroundImage: 'radial-gradient(1000px circle at var(--mouse-x, 50%) var(--mouse-y, 50%), rgba(255, 255, 255, 0.8), transparent 40%)', backgroundColor: 'transparent', }); }, }); } const isSafariBrowser = isSafari(); if (!isSafariBrowser) { // Apply webkitTextStroke only if not Safari gsap.set(structureLetters, { webkitTextStroke: 1, opacity: 1 }); structureLetters.forEach((letter) => { gsap.from(letter, { scrollTrigger: { trigger: letter, start: 'top 75%', toggleActions: 'play none none reverse', }, fontSize: '50rem', webkitTextStroke: 10, opacity: 1, ease: 'power4.in', onComplete: function () { const letterFilter: string = letter.getAttribute('structure-letter') || ''; if (letterFilter !== '') { revealStructureInfo(letterFilter); borderLightUp(letterFilter); } const rect = letter.getBoundingClientRect(); const containerRect = document.querySelector('#cards')!.getBoundingClientRect(); const x = rect.left + rect.width / 2 - containerRect.left; const y = rect.top + rect.height / 2 - containerRect.top; shockwaveActivate(x, y); }, onReverseComplete: function () { const letterFilter: string = letter.getAttribute('structure-letter') || ''; if (letterFilter !== '') { hideStructureInfo(letterFilter); } }, }); }); } else { gsap.set(structureLetters, { opacity: 1 }); structureLetters.forEach((letter) => { gsap.from(letter, { scrollTrigger: { trigger: letter, start: 'top 75%', toggleActions: 'play none none reverse', }, fontSize: '50rem', opacity: 1, ease: 'power4.in', onComplete: function () { const letterFilter: string = letter.getAttribute('structure-letter') || ''; if (letterFilter !== '') { revealStructureInfo(letterFilter); borderLightUp(letterFilter); } const rect = letter.getBoundingClientRect(); const containerRect = document.querySelector('#cards')!.getBoundingClientRect(); const x = rect.left + rect.width / 2 - containerRect.left; const y = rect.top + rect.height / 2 - containerRect.top; shockwaveActivate(x, y); }, onReverseComplete: function () { const letterFilter: string = letter.getAttribute('structure-letter') || ''; if (letterFilter !== '') { hideStructureInfo(letterFilter); } }, }); }); } } createStructureLettersAnimation(); //#endregion //#region How cards Animation //Child Hover Listenner for animation in css function createHowCardAnimations(breakpoint: string): void { const howWrappers = document.querySelectorAll('[how-card-expand_wrapper]'); const howCards = document.querySelector('[how-cards]'); // First, cleanup any previous animations/event listeners if (breakpoint === 'desktop') { cleanupAnimationsForElements(howWrappers, 'scroll'); } else { cleanupAnimationsForElements(howWrappers, 'event'); } if (breakpoint === 'desktop') { howWrappers.forEach((howWrapper) => { const card = howWrapper.querySelector('[how-card]'); if (!card) { logErrorMessage('Card not found'); return; } card.addEventListener('mouseover', () => { howWrapper.classList.add('expand'); }); card.addEventListener('mouseout', () => { howWrapper.classList.remove('expand'); }); }); if (howCards) { (howCards as HTMLElement).onmousemove = (e: MouseEvent) => { for (const howCard of document.querySelectorAll('[how-card]')) { if (howCard instanceof HTMLElement) { const rect = howCard.getBoundingClientRect(), x = e.clientX - rect.left, y = e.clientY - rect.top; howCard.style.setProperty('--mouse-x', `${x}px`); howCard.style.setProperty('--mouse-y', `${y}px`); } else { logErrorMessage('Expected an HTMLElement but found something else.'); } } }; } else { logErrorMessage("Element with ID 'how-card' not found"); } } else { howWrappers.forEach((howWrapper) => { const card = howWrapper.querySelector('[how-card]'); if (!card) { logErrorMessage('Card not found'); return; } // Assign a unique ID if needed if (!card.id) { card.id = `how-card-${Math.random().toString(36).substr(2, 9)}`; } gsap.to(card, { scrollTrigger: { id: card.id, // Assign a unique id to the ScrollTrigger instance trigger: card, start: 'top+=20px center', end: 'bottom-=20px center', toggleClass: { targets: howWrapper, className: 'expand' }, }, }); }); if (howCards) { document.onscroll = function () { for (const howCard of document.querySelectorAll('[how-card]')) { if (howCard instanceof HTMLElement) { const centerX = window.innerWidth / 2; const centerY = window.innerHeight / 2; const rect = howCard.getBoundingClientRect(); const x = centerX - rect.left; const y = centerY - rect.top; howCard.style.setProperty('--mouse-x', `${x}px`); howCard.style.setProperty('--mouse-y', `${y}px`); } else { logErrorMessage('Expected an HTMLElement but found something else.'); } } }; } else { logErrorMessage("Element with ID 'how-card' not found"); } } } //#endregion function breakpointListener(): void { const mediaQueryList = [ { media: '(min-width: 1280px)', breakpoint: 'desktop' }, { media: '(max-width: 1279px) and (min-width: 992px)', breakpoint: 'laptop', }, { media: '(max-width: 991px) and (min-width: 768px)', breakpoint: 'tablet', }, { media: '(max-width: 767px) and (min-width: 480px)', breakpoint: 'mobile-l', }, { media: '(max-width: 479px) and (min-width: 240px)', breakpoint: 'mobile-p', }, ]; mediaQueryList.forEach(({ media, breakpoint }) => { const mql = window.matchMedia(media); mql.addEventListener('change', (e) => { if (e.matches) { if (currentBreakpoint !== breakpoint) { currentBreakpoint = breakpoint; logBreakpointChange(breakpoint); createHowCardAnimations(breakpoint); } } }); if (mql.matches && currentBreakpoint !== breakpoint) { currentBreakpoint = breakpoint; logBreakpoint(breakpoint); createHowCardAnimations(breakpoint); } }); createCtaAnimation(); } breakpointListener(); //#endregion //#region Marquee Partner interface MarqueeOptions { wrapper: HTMLElement; itemSelector: string; direction: 'left' | 'right'; speed: number; } function setupMarquee({ wrapper, itemSelector, direction, speed }: MarqueeOptions) { const items = wrapper.querySelectorAll(itemSelector); if (items.length === 0) return; const marqueeContainer = document.createElement('div'); Object.assign(marqueeContainer.style, { display: 'flex', flexWrap: 'nowrap', position: 'relative', width: 'max-content', }); items.forEach((item) => marqueeContainer.appendChild(item.cloneNode(true))); items.forEach((item) => marqueeContainer.appendChild(item.cloneNode(true))); wrapper.innerHTML = ''; wrapper.appendChild(marqueeContainer); const updateMarquee = () => { const totalWidth = marqueeContainer.scrollWidth / 2; const initialPosition = direction === 'left' ? 0 : -totalWidth; gsap.set(marqueeContainer, { x: initialPosition }); gsap.to(marqueeContainer, { x: direction === 'left' ? `-=${totalWidth}px` : `+=${totalWidth}px`, ease: 'none', duration: totalWidth / speed, repeat: -1, onRepeat: () => { gsap.set(marqueeContainer, { x: initialPosition }); }, }); }; updateMarquee(); // Initial setup window.addEventListener('resize', () => { gsap.killTweensOf(marqueeContainer); // Stop the current animation updateMarquee(); // Recalculate and restart the animation }); } const speed = 100; const clientWrapper = document.querySelector('.client_wrapper') as HTMLElement; const partnerWrapper = document.querySelector('.partner_wrapper') as HTMLElement; if (clientWrapper) { setupMarquee({ wrapper: clientWrapper, itemSelector: '.client_collection_item', direction: 'left', speed: speed, }); } if (partnerWrapper) { setupMarquee({ wrapper: partnerWrapper, itemSelector: '.partner_collection_item', direction: 'right', speed: speed, }); } //#endregion //#region CTA marquee const marqueeSpeed: number = 1500; // Velocity in pixels total pixels during all scroll. function debounce(func: () => void, wait: number) { let timeout: number | null = null; return function () { if (timeout !== null) { clearTimeout(timeout); } timeout = window.setTimeout(func, wait); }; } function cloneMarquee(wrapper: HTMLElement) { const parent = wrapper.parentElement; if (parent) { const clone = wrapper.cloneNode(true) as HTMLElement; parent.appendChild(clone); } } function clearClones(wrapper: HTMLElement) { const clones = wrapper.parentElement?.querySelectorAll('.cloned'); clones?.forEach((clone) => clone.remove()); } function startMarqueeScrollAnimation() { const rightMarquee = document.querySelector('[marquee_wrapper="right"]') as HTMLElement; const leftMarquee = document.querySelector('[marquee_wrapper="left"]') as HTMLElement; if (rightMarquee && leftMarquee) { clearClones(rightMarquee); clearClones(leftMarquee); cloneMarquee(rightMarquee); cloneMarquee(leftMarquee); const distanceToMove = marqueeSpeed; const rightMarqueeWrapper = rightMarquee.parentElement; const leftMarqueeWrapper = leftMarquee.parentElement; if (rightMarqueeWrapper && leftMarqueeWrapper) { gsap.set(leftMarqueeWrapper, { x: () => `-${leftMarquee.offsetWidth}px`, }); gsap.to(rightMarqueeWrapper, { x: `-=${distanceToMove}px`, ease: 'none', scrollTrigger: { trigger: rightMarquee, start: 'top bottom', end: 'bottom top', scrub: true, }, }); gsap.to(leftMarqueeWrapper, { x: `+=${distanceToMove}px`, ease: 'none', scrollTrigger: { trigger: leftMarquee, start: 'top bottom', end: 'bottom top', scrub: true, }, }); } } } window.addEventListener('load', startMarqueeScrollAnimation); // Debounced resize event handling to prevent crashes window.addEventListener( 'resize', debounce(() => { startMarqueeScrollAnimation(); }, 200) ); //#endregion function openModal(event: Event, modalType: string, id: number): void { logMessage(`Open modal ${modalType} triggered`); event.preventDefault(); // Prevent default action if it is a link // Log the clicked element const clickedElement = event.currentTarget as HTMLElement; logMessage('Clicked element:', clickedElement.toString()); logMessage('Clicked id:', id.toString()); const clickedName = clickedElement.getAttribute(`${modalType.toLowerCase()}_link-name`); if (clickedName) { logMessage('Clicked Item name:', clickedName); } const cmsFilter = document.querySelector(`[modal_wrapper='${modalType}']`); const cmsFilterItems = cmsFilter?.querySelectorAll( `[${modalType}-collection_item]` ) as NodeListOf; logMessage('cmsFilterItems:', cmsFilterItems.toString()); cmsFilterItems.forEach((item) => { const name = item.getAttribute('item-name'); if (name) { logMessage('Item', item.toString(), 'Name:', name); } if (name === clickedName) { item.style.display = 'flex'; } else { item.style.display = 'none'; } }); gsap.set(`[modal_container='${modalType}']`, { opacity: 0, display: 'flex', }); gsap.set(`[modal_wrapper='${modalType}']`, { //top: "100vh", rotationX: 90, transformPerspective: 2500, transformOrigin: 'center center', }); gsap.to(`[modal_container='${modalType}']`, { opacity: 1, duration: 0.3, ease: 'power1.out', }); gsap.to(`[modal_wrapper='${modalType}']`, { //top: "0vh", duration: 0.5, rotationX: 0, ease: 'power1.out', }); } function closeModal(event: Event): void { logMessage('Close modal triggered'); event.preventDefault(); // Prevent default action if it is a link gsap.to('[modal_wrapper]', { //top: "100vh", rotationX: 90, duration: 0.4, ease: 'power1.out', }); gsap.to('[modal_container]', { opacity: 0, duration: 0.5, ease: 'power1.out', onComplete: function () { gsap.set('[modal_container]', { display: 'none', }); }, }); } function scrollTo(event: Event, section: HTMLElement): void { const triggeredSection: string | undefined = section.getAttribute('wb-section')?.toString(); if (triggeredSection) { logMessage('Scroll triggered for section: ', triggeredSection); } function easeOutQuad(x: number): number { return 1 - (1 - x) * (1 - x); } event.preventDefault(); // Prevent default action if it is a link lenis.scrollTo(section, { duration: 2, // Duration in seconds easing: easeOutQuad, // Use the ease out quad easing function }); } // Function to reaveal Navbar BG outside Hero Section function revealNavBG(): void { //Initial State gsap.set(navBG, { opacity: 0 }); // Scroll trigger ScrollTrigger.create({ trigger: HeroSection, start: 'bottom bottom', end: 'bottom top', scrub: true, // Synchronize the animation with the scroll position onUpdate: (self) => { const { progress } = self; gsap.to(navBG, { duration: 1, opacity: progress }); }, onLeave: () => {}, }); } // Function to scroll to Nav Link correspondent Section function navLinkTo(Link: HTMLElement, linkName: string | null): void { Link.addEventListener('click', (event) => { event.preventDefault(); // Find the matching section const targetSection = Array.from(sections).find( (section) => section.getAttribute('wb-section') === linkName ) as HTMLElement; logMessage('targetSection:', targetSection.toString()); if (targetSection && targetSection instanceof HTMLElement) { // Scroll to the matching section scrollTo(event, targetSection); } else { logErrorMessage(`Section with wb-section='${linkName}' not found`); } }); } //#region Sections Declaring const sections = document.querySelectorAll('[wb-section]'); const NavBarSection = document.querySelector("[wb-section='navbar']"); const SectionPartner = document.querySelector("[wb-section='partner']"); const HeroSection = document.querySelector("[wb-section='hero']"); const ExpertiseSection = document.querySelector("[wb-section='expertise']"); const EstruturaSection = document.querySelector("[wb-section='estrutura']"); const SolucoesSection = document.querySelector("[wb-section='solucoes']"); logMessage('wb-sections:', sections.toString()); if (NavBarSection) logMessage("wb-section='Navbar'", NavBarSection.toString()); if (SectionPartner) logMessage("wb-section='Partner':", SectionPartner.toString()); if (HeroSection) logMessage("wb-section='Hero':", HeroSection.toString()); if (ExpertiseSection) logMessage("wb-section='Expertise_Title'", ExpertiseSection.toString()); if (EstruturaSection) logMessage("wb-section='Estrutura:", EstruturaSection.toString()); if (SolucoesSection) logMessage("wb-section='Solucoes':", SolucoesSection.toString()); // Nav BG Declaring const navBG = document.querySelector("[wb-background='nav_BG']"); if (navBG) logMessage('navBG:', navBG.toString()); if (navBG && HeroSection) { revealNavBG(); } else { logErrorMessage("wb-section=Hero or wb-background='nav_BG' not found"); } //#endregion //#region Nav Links Event listener const NavLinks = document.querySelectorAll('[wb-nav-link]'); const MenuLinks = document.querySelectorAll('[wb-textfx-menu]'); if (MenuLinks.length > 0) { MenuLinks.forEach((Link) => { const linkName = Link.getAttribute('wb-textfx-menu'); navLinkTo(Link as HTMLElement, linkName); }); } else { logErrorMessage('wb-textfx-menu: not found'); } if (NavLinks.length > 0) { NavLinks.forEach((Link) => { const linkName = Link.getAttribute('wb-nav-link'); navLinkTo(Link as HTMLElement, linkName); }); } else { logErrorMessage('wb-nav-link: not found'); } const FooterLinks = document.querySelectorAll('[FooterLink]'); if (FooterLinks.length > 0) { FooterLinks.forEach((Link) => { const linkName = Link.getAttribute('FooterLink'); navLinkTo(Link as HTMLElement, linkName); }); } else { logErrorMessage('wb-textfx-menu: not found'); } //#endregion //#region Contato Links Event listeners const contatoUrl = 'https://api.whatsapp.com/send?phone=5531972319470&text=Ol%C3%A1%2C%20amei%20o%20studio!%20%0A%20Gostaria%20de%20marcar%20uma%20demonstra%C3%A7%C3%A3o.'; const contatoUrlStudioX = 'https://api.whatsapp.com/send?phone=5531972319470&text=Ol%C3%A1%2C%20amei%20o%20studio!%20%0A%20Gostaria%20de%20agendar%20uma%20visita%20no%20studio%20X.'; const contatoUrlStudioR = 'https://api.whatsapp.com/send?phone=5531972319470&text=Ol%C3%A1%2C%20amei%20o%20studio!%20%0A%20Gostaria%20de%20agendar%20uma%20visita%20no%20studio%20R.'; const contatoLink = document.querySelectorAll('[contatolink]'); logErrorMessage('contatoLink:', contatoLink.toString()); if (contatoLink) { contatoLink.forEach((Link) => { Link.addEventListener('click', (event) => { if (contatoUrl) { event.preventDefault(); const linkValue = Link.getAttribute('contatolink'); if (linkValue === 'x') { window.open(contatoUrlStudioX, '_blank'); // Opens the URL in a new tab } else if (linkValue === 'r') { window.open(contatoUrlStudioR, '_blank'); // Opens the URL in a new tab } else { window.open(contatoUrl, '_blank'); // Opens the URL in a new tab } } }); }); } else { logErrorMessage('[contatoLink] not found'); } //#endregion //#region Scroll Down Hero link Event listener const scrollDownLink = document.querySelector('[ScrollDownLink]'); if (scrollDownLink) logMessage('scrollDownLink:', scrollDownLink.toString()); if (scrollDownLink) { scrollDownLink.addEventListener('click', (event) => scrollTo(event, SolucoesSection as HTMLElement) ); } else { logErrorMessage('[ScrollDownLink] not found'); } //#endregion //#region Scroll Up Footer Logo Event listener const FooterLogo = document.querySelector("[Footer_Link='Logo']"); if (scrollDownLink) logMessage("Footer_Link='Logo':", scrollDownLink.toString()); if (FooterLogo && HeroSection) { FooterLogo.addEventListener('click', (event) => scrollTo(event, HeroSection as HTMLElement)); } else { logErrorMessage('[FooterLogo] not found'); } //#endregion //#region Modal Event listeners function addEventListeners(modalType: string): void { const modalLinks = document.querySelectorAll(`[open-modal_link='${modalType}']`); const modalCover = document.querySelector(`[modal_cover='${modalType}']`); const closeLink = document.querySelector(`[close-modal_link='${modalType}']`); logMessage(`${modalType} Links:`, modalLinks.toString()); if (modalCover) logMessage(`${modalType} modalCover:`, modalCover.toString()); if (closeLink) logMessage(`${modalType} closeLink:`, closeLink.toString()); if (modalLinks.length > 0) { modalLinks.forEach((link, index) => { link.addEventListener('click', (event) => openModal(event, modalType, index)); }); } else { logErrorMessage(`[open-modal_link='${modalType}'] not found`); } if (modalCover) { modalCover.addEventListener('click', closeModal); } else { logErrorMessage(`modal_cover='${modalType}' not found`); } if (closeLink) { closeLink.addEventListener('click', closeModal); } else { logErrorMessage(`close-modal_link='${modalType}' not found`); } } addEventListeners('solucoes'); addEventListeners('expertise'); addEventListeners('structure'); //#endregion //#region Animations function closeButtonAnimations() { const closeButtons = document.querySelectorAll('[close-link]'); closeButtons.forEach((button) => { const closeCircle = button.querySelector('[close-circle]'); const closeIcon = button.querySelector('[close-icon], .svg'); if (!closeCircle || !closeIcon) return; button.addEventListener('mouseenter', () => { gsap.to(closeCircle, { backgroundColor: 'rgb(49, 49, 49, 1)', scale: 1.1, duration: 0.3, ease: 'power1.out', }); gsap.to(closeIcon, { scale: 1.2, rotateZ: 90, duration: 0.3, ease: 'power2.in', }); }); // Create the hover out animation button.addEventListener('mouseleave', () => { gsap.to(closeCircle, { backgroundColor: 'rgb(37, 37, 39, 0.8)', scale: 1, duration: 0.3, ease: 'power1.in', }); gsap.to(closeIcon, { scale: 1, rotateZ: 0, duration: 0.3, ease: 'power2.out', }); }); }); } closeButtonAnimations(); function rotateOnScrollAnimation() { const rotateElements = document.querySelectorAll('[rotate_on-scroll]'); rotateElements.forEach((element) => { gsap.from(element, { scrollTrigger: { trigger: element, start: 'top-=200 bottom', end: 'bottom bottom', scrub: true, }, rotateX: 80, rotateY: 30, rotateZ: -30, ease: 'power1.in', }); }); } rotateOnScrollAnimation(); function thumbHover(): void { const solucoesVideoItens = document.querySelectorAll('[solucoes-video_item]'); solucoesVideoItens.forEach((element) => { const thumboverlay = element.querySelector('[thumb_overlay]'); const thumbInfoWrapper = element.querySelector('[thumb-info_wrapper]'); const thumbSVG = element.querySelector('[play-svg_wrapper]'); const matchMedia = gsap.matchMedia(); matchMedia.add('(min-width: 992px)', () => { gsap.set(thumbInfoWrapper, { bottom: '15%', }); gsap.set(thumbSVG, { opacity: 0, }); gsap.set(thumboverlay, { backgroundColor: 'rgba(5, 5, 6, 0)', }); // Define the mouseenter event handler const handleMouseEnter = () => { gsap.killTweensOf([thumbInfoWrapper, thumbSVG, thumboverlay]); gsap.fromTo( thumbInfoWrapper, { bottom: '15%', }, { bottom: '50%', ease: 'power3.out', duration: 0.3, } ); gsap.fromTo( thumbSVG, { opacity: 0, }, { opacity: 1, ease: 'power1.in', duration: 0.3, } ); gsap.fromTo( thumboverlay, { backgroundColor: 'rgba(5, 5, 6, 0)', }, { backgroundColor: 'rgba(5, 5, 6, 0.7)', ease: 'power1.in', duration: 0.3, } ); }; // Define the mouseleave event handler const handleMouseLeave = () => { gsap.killTweensOf([thumbInfoWrapper, thumbSVG, thumboverlay]); gsap.to(thumbInfoWrapper, { bottom: '15%', ease: 'power1.out', duration: 0.3, }); gsap.to(thumbSVG, { opacity: 0, ease: 'power2.out', duration: 0.3, }); gsap.to(thumboverlay, { backgroundColor: 'rgba(5, 5, 6, 0)', ease: 'power1.out', duration: 0.3, }); }; // Add event listeners element.addEventListener('mouseenter', handleMouseEnter); element.addEventListener('mouseleave', handleMouseLeave); // Cleanup function to remove event listeners when the media query no longer matches return () => { element.removeEventListener('mouseenter', handleMouseEnter); element.removeEventListener('mouseleave', handleMouseLeave); gsap.set(thumbInfoWrapper, { bottom: '50%', }); gsap.set(thumbSVG, { opacity: 100, }); gsap.set(thumboverlay, { backgroundColor: 'rgba(5, 5, 6, .15)', }); }; }); }); } thumbHover(); interface AnimationConfig { start: string; properties: gsap.TweenVars; } const mmStAnimations = gsap.matchMedia(); function createAnimation(element: Element, animationConfig: AnimationConfig) { const tl = gsap.timeline({ scrollTrigger: { trigger: element, start: animationConfig.start, toggleActions: 'play none none reverse', }, }); tl.from(element, animationConfig.properties); } function applyAnimationToElements(selector: string, animationConfig: AnimationConfig) { const elements = document.querySelectorAll(selector); elements.forEach((element) => { createAnimation(element, animationConfig); }); } mmStAnimations.add('(min-width: 992px)', () => { const animationConfig: AnimationConfig = { start: 'top 75%', properties: { rotateY: 90, opacity: 0, ease: 'power3.out', duration: 0.5, }, }; applyAnimationToElements('[st_y-flip]', animationConfig); applyAnimationToElements('[st_x-flip]', { ...animationConfig, properties: { rotateX: 90, opacity: 0 }, }); applyAnimationToElements('[st_up]', { ...animationConfig, properties: { translateY: '300%', opacity: 0 }, }); applyAnimationToElements('[st_right]', { ...animationConfig, properties: { translateX: '-300%', opacity: 0, delay: 0.3, duration: 0.7 }, }); applyAnimationToElements('[st_opacity]', { ...animationConfig, properties: { opacity: 0 } }); function stYFlipStagger02() { const stYFlipStagger02Elements = document.querySelectorAll('[st_y-flip_stagger-02]'); gsap.from(stYFlipStagger02Elements, { scrollTrigger: { trigger: stYFlipStagger02Elements, start: 'top 70%', toggleActions: 'play none none reverse', }, rotateY: 90, opacity: 0, stagger: { each: 0.1, from: 'random', }, ease: 'power3.out', }); } stYFlipStagger02(); }); mmStAnimations.add('(max-width: 991px)', () => { const animationConfig: AnimationConfig = { start: 'top 90%', properties: { rotateY: 90, opacity: 0, ease: 'power3.out', duration: 0.5, }, }; applyAnimationToElements('[st_y-flip]', animationConfig); applyAnimationToElements('[st_x-flip]', { ...animationConfig, properties: { rotateX: 90, opacity: 0 }, }); applyAnimationToElements('[st_up]', { ...animationConfig, properties: { translateY: '300%', opacity: 0 }, }); applyAnimationToElements('[st_right]', { ...animationConfig, properties: { translateX: '-300%', opacity: 0, delay: 0.3, duration: 0.7 }, }); applyAnimationToElements('[st_opacity]', { ...animationConfig, properties: { opacity: 0 } }); }); function stYFlipStagger01() { const stYFlipStagger01Elements = document.querySelectorAll('[st_y-flip_stagger-01]'); gsap.from(stYFlipStagger01Elements, { scrollTrigger: { trigger: stYFlipStagger01Elements, start: 'top 95%', toggleActions: 'play none none reverse', }, rotateY: 90, opacity: 0, stagger: { each: 0.1, from: 'random', }, ease: 'power3.out', }); } stYFlipStagger01(); function stFooterLink() { const stFooterLinkElements = document.querySelectorAll('.footer_link'); gsap.from(stFooterLinkElements, { scrollTrigger: { start: 'bottom-=400dvh 100%', toggleActions: 'play none none reverse', }, rotateY: 90, opacity: 0, stagger: { each: 0.1, from: 'random', }, ease: 'power3.out', }); } stFooterLink(); function stInterIm() { const stInter = document.querySelector('[st_inter]'); const stIm = document.querySelector('[st_im]'); if (!stInter || !stIm) return; const tlInterIM = gsap.timeline({ scrollTrigger: { start: 'bottom-=250dvh 100%', toggleActions: 'play none none reverse', }, ease: 'power4.in', }); const glowShadowIM = ` 1px 1px 4px rgb(23, 106, 197), -1px -1px 8px rgb(23, 106, 197), -1px 1px 10px rgb(23, 106, 197), 1px -1px 10px rgb(23, 106, 197), 0px 0px 20px rgb(23, 106, 197)`; const glowShadowInter = ` 1px 1px 4px rgb(255, 121, 54), -1px -1px 8px rgb(255, 121, 54), -1px 1px 10px rgb(255, 121, 54), 1px -1px 10px rgb(255, 121, 54), 0px 0px 20px rgb(255, 121, 54)`; tlInterIM.from(stInter, { fontSize: '2rem', webkitTextFillColor: 'rgb(255, 255, 255)', opacity: 0, onComplete: function () { gsap.to(stInter, { textShadow: glowShadowInter, yoyo: true, repeat: 1, ease: 'power2.out', onComplete: function () { gsap.to(stInter, { webkitTextFillColor: 'rgb(05, 05, 05)', }); }, }); }, }); tlInterIM.from(stIm, { fontSize: '2rem', webkitTextFillColor: 'rgb(255, 255, 255)', opacity: 0, delay: 0.05, onComplete: function () { gsap.to(stIm, { textShadow: glowShadowIM, yoyo: true, repeat: 1, ease: 'power2.out', onComplete: function () { gsap.to(stIm, { webkitTextFillColor: 'rgb(05, 05, 05)', }); }, }); }, }); stInter.addEventListener('mouseenter', () => { gsap.to(stInter, { webkitTextFillColor: 'rgb(255, 255, 255)', textShadow: glowShadowInter, }); }); stInter.addEventListener('mouseleave', () => { gsap.to(stInter, { webkitTextFillColor: 'rgb(05, 05, 05)', textShadow: 'none', }); }); stIm.addEventListener('mouseenter', () => { gsap.to(stIm, { webkitTextFillColor: 'rgb(255, 255, 255)', textShadow: glowShadowIM, }); }); stIm.addEventListener('mouseleave', () => { gsap.to(stIm, { webkitTextFillColor: 'rgb(05, 05, 05)', textShadow: 'none', }); }); } stInterIm(); function stGlow() { const stGlowElements = document.querySelectorAll('[glow-st]'); if (!stGlowElements) return; const glowShadow = ` 1px 1px 4px rgb(23, 106, 197), -1px -1px 8px rgb(23, 106, 197), -1px 1px 10px rgb(23, 106, 197), 1px -1px 10px rgb(23, 106, 197), 0px 0px 20px rgb(23, 106, 197), 0px 0px 10px rgb(23, 106, 197) inset, 0px 0px 20px rgb(23, 106, 197) inset, 0px 0px 30px rgb(23, 106, 197) inset`; const glowShadowNone = ` 1px 1px 4px rgba(23, 106, 197, 00), -1px -1px 8px rgba(23, 106, 197, 00), -1px 1px 10px rgba(23, 106, 197, 00), 1px -1px 20px rgba(23, 106, 197, 00), 1px -1px 40px rgba(23, 106, 197, 00), 0px 0px 60px rgba(23, 106, 197, 00), 0px 0px 10px rgba(23, 106, 197, 00) inset, 0px 0px 20px rgba(23, 106, 197, 00) inset, 0px 0px 30px rgba(23, 106, 197, 00) inset`; const glowShadowText = ` 1px 1px 4px rgb(23, 106, 197), -1px -1px 8px rgb(23, 106, 197), -1px 1px 10px rgb(23, 106, 197), 1px -1px 20px rgb(23, 106, 197), 1px -1px 40px rgb(23, 106, 197), 0px 0px 60px rgb(23, 106, 197)`; const glowShadowTextNone = ` 1px 1px 4px rgba(23, 106, 197, 00), -1px -1px 8px rgba(23, 106, 197, 00), -1px 1px 10px rgba(23, 106, 197, 00), 1px -1px 20px rgba(23, 106, 197, 00), 1px -1px 40px rgba(23, 106, 197, 00), 0px 0px 60px rgba(23, 106, 197, 00)`; stGlowElements.forEach((stGlowElement) => { if (stGlowElement.nodeName === 'H5') { const elementContainer = stGlowElement.parentElement?.parentElement?.parentElement; gsap.to(stGlowElement, { scrollTrigger: { trigger: elementContainer, start: 'bottom 100%', toggleActions: 'play reset none reset', }, textShadow: glowShadowText, duration: 1.5, ease: 'power4.out', onComplete: function () { gsap.to(stGlowElement, { textShadow: glowShadowTextNone, duration: 1.5, ease: 'power1.out', }); }, }); } else { const elementContainer = stGlowElement.parentElement?.parentElement; gsap.to(stGlowElement, { scrollTrigger: { trigger: elementContainer, start: 'bottom 100%', toggleActions: 'play reset none reset', }, boxShadow: glowShadow, duration: 1.5, ease: 'power4.out', onComplete: function () { gsap.to(stGlowElement, { boxShadow: glowShadowNone, duration: 1, ease: 'power1.out', }); }, }); } }); } stGlow(); //#endregion //#region Structure & Solucoes Card listeners const cards = document.querySelector('[cards]'); if (cards) { (cards as HTMLElement).onmousemove = (e) => { for (const card of document.querySelectorAll('[card]')) { if (card instanceof HTMLElement) { const rect = card.getBoundingClientRect(), x = e.clientX - rect.left, y = e.clientY - rect.top; card.style.setProperty('--mouse-x', `${x}px`); card.style.setProperty('--mouse-y', `${y}px`); } else { logErrorMessage('Expected an HTMLElement but found something else.'); } } }; } else { logErrorMessage("Element with ID 'card' not found"); } const swiperContainer = document.querySelector('.swiper'); if (swiperContainer) { (swiperContainer as HTMLElement).onmousemove = (e) => { for (const swiperItem of document.querySelectorAll('.swiper-slide')) { if (swiperItem instanceof HTMLElement) { const rect = swiperItem.getBoundingClientRect(), x = e.clientX - rect.left, y = e.clientY - rect.top; swiperItem.style.setProperty('--mouse-x', `${x}px`); swiperItem.style.setProperty('--mouse-y', `${y}px`); } else { logErrorMessage('Expected an HTMLElement but found something else.'); } } }; } else { logErrorMessage("Element with ID 'card' not found"); } //#endregion //#region Swiper const swiperSolucoesElement = document.querySelector('[swiper-solucoes]'); const swiperLightboxElement = document.querySelector('.swiper-lightbox'); const swiperLightboxThumbsElement = document.querySelector('.swiper-lightbox-thumbs'); if (swiperSolucoesElement) { const swiperSolucoesParams: SwiperOptions = { modules: [A11y, Autoplay, EffectCoverflow, Keyboard, Navigation], effect: 'coverflow', grabCursor: true, centeredSlides: true, slidesPerView: 1.2, slideToClickedSlide: true, loop: true, allowTouchMove: true, createElements: true, navigation: true, speed: 500, loopAdditionalSlides: 2, autoplay: { delay: 3000, pauseOnMouseEnter: true, }, coverflowEffect: { depth: 250, rotate: 7, slideShadows: true, }, a11y: { prevSlideMessage: 'Previous slide', nextSlideMessage: 'Next slide', }, keyboard: { enabled: true, onlyInViewport: false, }, // Responsive breakpoints breakpoints: { // when window width is >= 767px 767: { slidesPerView: 1.5, }, 991: { slidesPerView: 2, }, 1279: { slidesPerView: 2.8, }, }, on: { slideChangeTransitionStart: function () { updateActiveSlide(); }, init: function () { updateActiveSlide(); }, touchEnd: function () { updateActiveSlide(); }, }, }; const swiper = new Swiper('[swiper-solucoes]', swiperSolucoesParams); swiper.init(); function updateActiveSlide() { // Get all slides and pagination items const allSlides = document.querySelectorAll('[swiper-slide]'); const allPaginationItems = document.querySelectorAll('.solucoes-pagination_item'); // Get the currently active slide const activeSlide = document.querySelector('.swiper-slide-active'); if (!activeSlide) return; // Get the name of the active slide const activeSlideName = activeSlide.getAttribute('solucoes_link-name'); // Iterate over all slides and update the classes allSlides.forEach((slide) => { //const slideTitle = slide.querySelector('.swiper-slide-title'); const slidePlayIcon = slide.querySelector('[play-icon_wrapper]'); if (!slidePlayIcon) return; if (slide === activeSlide) { //slideTitle.classList.remove('outline-white'); gsap.to(slidePlayIcon, { opacity: 1, ease: 'power3.out', duration: 1, }); } else { //slideTitle.classList.add('outline-white'); gsap.to(slidePlayIcon, { opacity: 0, ease: 'power3.out', duration: 1, }); } }); // Iterate over all pagination items and update the classes allPaginationItems.forEach((item) => { const paginationName = item.getAttribute('solucoes_link-name'); const paginationTitle = item.querySelector('.solucoes-pagination_title'); if (paginationTitle) { if (paginationName === activeSlideName) { paginationTitle.classList.remove('outline-white'); } else { paginationTitle.classList.add('outline-white'); } } }); const paginationItems = document.querySelectorAll('.solucoes-pagination_item'); paginationItems.forEach((item) => { item.addEventListener('mouseenter', () => { const targetName = item.getAttribute('solucoes_link-name'); const targetIndex = Array.from(swiper.slides).findIndex( (slide) => slide.getAttribute('solucoes_link-name') === targetName ); if (targetIndex !== -1) { swiper.slideTo(targetIndex); } }); }); } } else { console.error('Swiper element not found'); } if (!swiperLightboxElement || !swiperLightboxThumbsElement) return; const swiperLightboxThumbs = new Swiper('[swiper-lightbox-thumbs]', { modules: [A11y, Autoplay, EffectCoverflow, Keyboard, Navigation, Controller], centeredSlides: true, slidesPerView: 3.5, spaceBetween: 5, slideToClickedSlide: true, keyboard: { enabled: true, onlyInViewport: false, }, breakpoints: { // when window width is >= 1279px 1279: { slidesPerView: 5.5, spaceBetween: 10, }, }, }); const swiperLightbox = new Swiper('[swiper-lightbox]', { modules: [A11y, Autoplay, EffectCoverflow, Keyboard, Navigation, Controller], effect: 'fade', grabCursor: true, slidesPerView: 1, allowTouchMove: true, createElements: true, navigation: true, a11y: { prevSlideMessage: 'Previous slide', nextSlideMessage: 'Next slide', }, keyboard: { enabled: true, onlyInViewport: false, }, }); swiperLightbox.controller.control = swiperLightboxThumbs; swiperLightboxThumbs.controller.control = swiperLightbox; swiperLightboxThumbs.init(); swiperLightbox.init(); //#endregion //#region Lightbox function openLightbox(event: Event, gallery: string) { event.preventDefault(); // Prevent default action if it is a link const images = document.querySelectorAll(`[lightbox="${gallery}"]`); const swiperWrapper = document.querySelector('[lightbox-swiper-wrapper]'); const thumbWrapper = document.querySelector('[lightbox-thumbs-wrapper]'); const lightboxFixed = document.querySelector('[lightbox-fixed]'); if (!swiperWrapper || !thumbWrapper || !lightboxFixed) return; swiperWrapper.innerHTML = ''; // Clear any existing slides thumbWrapper.innerHTML = ''; // Clear any existing thumb slides // Populate the lightbox with the selected gallery images images.forEach((image, index) => { const imgSrc = image.getAttribute('src'); const imgAlt = image.getAttribute('alt') || ''; // Check if the src contains "placeholder" to skip placeholder images if (imgSrc && !imgSrc.includes('placeholder')) { const newSlide = document.createElement('div'); newSlide.className = 'swiper-slide'; newSlide.setAttribute('role', 'group'); newSlide.setAttribute('aria-label', `${index + 1} / ${images.length}`); newSlide.innerHTML = `${imgAlt}`; swiperWrapper.appendChild(newSlide); // Create corresponding thumbnail slide const newThumb = document.createElement('div'); newThumb.className = 'swiper-slide'; newThumb.setAttribute('role', 'group'); newThumb.setAttribute('aria-label', `${index + 1} / ${images.length}`); newThumb.innerHTML = `${imgAlt}`; thumbWrapper.appendChild(newThumb); } }); // Initialize or update Swiper instances if (swiperLightbox) { swiperLightbox.update(); swiperLightboxThumbs.update(); } // Set the initial slide to the clicked image if (event.currentTarget instanceof Element) { const clickedIndex = Array.from(images).indexOf(event.currentTarget); swiperLightbox.slideTo(clickedIndex, 0); } // Show the lightbox gsap.set(lightboxFixed, { opacity: 0, display: 'flex', }); gsap.set('[lightbox_wrapper]', { rotationX: 90, transformPerspective: 2500, transformOrigin: 'center center', }); gsap.to(lightboxFixed, { opacity: 1, duration: 0.3, ease: 'power1.out', }); gsap.to('[lightbox_wrapper]', { duration: 0.5, rotationX: 0, ease: 'power1.out', }); } function closeLightbox(event: Event) { event.preventDefault(); // Prevent default action if it is a link gsap.to('[lightbox_wrapper]', { rotationX: 90, duration: 0.4, ease: 'power1.out', }); gsap.to('[lightbox-fixed]', { opacity: 0, duration: 0.5, ease: 'power1.out', onComplete: function () { gsap.set('[lightbox-fixed]', { display: 'none', }); }, }); } const lightboxLinks = document.querySelectorAll('[lightbox]'); const lightboxCloseLinks = document.querySelectorAll('[lightbox_close]'); const lightboxCover = document.querySelector('[lightbox_close]'); if (lightboxLinks.length > 0) { lightboxLinks.forEach((link) => { const gallery = link.getAttribute('lightbox'); if (gallery) { link.addEventListener('click', (event) => openLightbox(event, gallery)); } }); } else { console.error(`[Openlightbox='${lightboxLinks}'] not found`); } gsap.set('[lightbox-fixed]', { display: 'none' }); if (lightboxCloseLinks.length > 0) { lightboxCloseLinks.forEach((link) => { link.addEventListener('click', (event) => closeLightbox(event)); }); } else { console.error(`[Openlightbox='${lightboxCloseLinks}'] not found`); } // Close lightbox when clicking outside of the image if (lightboxCover) { lightboxCover.addEventListener('click', (event) => closeLightbox(event)); } //#endregion } catch (error) { console.error('An error occurred:', error); } });