PageSourceSearch

https://thyca.org/wp-content/themes/thyca/assets/js/custom/03-animation.js?ver=789992091

js thyca.org collected 2026-09-24 19:16:49 UTC 8,428 bytes, 233 lines download raw bytes

1(function (app) {
2    "use strict";
3
4    var Animation = function () { };
5
6    Animation.prototype.init = function () {
7        // Animation.prototype.transitionPresets();
8        Animation.prototype.handleNav();
9        Animation.prototype.handle404();
10    };
11
12    Animation.prototype.handleNav = function () {
13        const nav = $("nav");
14        if (!nav.length) return;
15
16        function toggleNav() {
17            ScrollTrigger.create({
18                trigger: "body",
19                start: "top top",
20                onUpdate: (self) => {
21                    if (self.direction === 1) {
22                        hideHeader(true);
23                    } else {
24                        hideHeader(false);
25                    }
26                },
27            });
28
29            function hideHeader(state) {
30                if (state) {
31                    if (nav.hasClass("nav-hidden") || nav.hasClass("mob-active")) return;
32                    nav.addClass("nav-hidden");
33                } else {
34                    if (!nav.hasClass("nav-hidden")) return;
35                    nav.removeClass("nav-hidden");
36                }
37            }
38        }
39
40        function mobileNavDropdown() {
41            let mm = gsap.matchMedia();
42        
43            mm.add(
44                {
45                    isDesktop: `(min-width: 1200px)`,
46                    isMobile: `(max-width: 1199.98px)`,
47                },
48                (context) => {
49                    let { isDesktop, isMobile } = context.conditions;
50        
51                    const items = $(".nav__acc");
52                    const linkHeads = $(".nav__acc .nav__acc-head"); // Make sure to select all nav heads
53                    if (!items.length) return;
54        
55                    if (isDesktop) {
56                        items.removeClass("active");
57                        linkHeads.off("click");
58                    }
59        
60                    if (isMobile) {
61                        // Add a click handler only once per head
62                        linkHeads.off("click").on("click", function (e) {
63                            // Prevent the event from bubbling up to parent elements
64                            e.stopPropagation();
65        
66                            const head = $(this); // Get the clicked head
67                            const subSelf = head.closest(".nav__acc"); // Find the closest nav__acc parent
68        
69                            // Toggle the active class on the specific nav__acc
70                            if (!subSelf.hasClass("active")) {
71                                subSelf.addClass("active");
72                            } else {
73                                subSelf.removeClass("active");
74                            }
75                        });
76                    }
77        
78                    return () => { };
79                }
80            );
81        }
82
83        function burgerEvent() {
84            const burger = nav.find(".nav__burger");
85            let mm = gsap.matchMedia();
86
87            mm.add(
88                {
89                    isDesktop: `(min-width: 1400px)`,
90                    isMobile: `(max-width: 1399.98px)`,
91                },
92                (context) => {
93                    let { isDesktop, isMobile } = context.conditions;
94
95                    if (isDesktop) {
96                        nav.removeClass("mob-active");
97                        $("html").removeClass("disable-scrolling");
98                        burger.off("click");
99                    }
100
101                    if (isMobile) {
102                        burger.click(function () {
103                            nav.toggleClass("mob-active");
104
105                            if (nav.hasClass("mob-active")) {
106                                nav.find(".nav__acc").removeClass("active");
107                            }
108
109                            $("html").toggleClass("disable-scrolling");
110                        });
111                    }
112
113                    return () => { };
114                }
115            );
116        }
117
118        function highlightActiveLink(navSelector) {
119            const currentUrl = window.location.href;
120        
121            // Handle parent .nav__link
122            const parentLinks = $(`${navSelector} .nav__item.parent .nav__link`);
123            parentLinks.each(function () {
124                const parentLink = $(this);
125                const childLinks = parentLink.closest(".nav__item").find(".nav__child"); // Find child links under this parent
126        
127                let isActive = false; // Flag to check if any child is active
128        
129                // Check if any child link matches the current URL
130                childLinks.each(function () {
131                    const childLink = $(this);
132                    const childHref = childLink.attr("href");
133        
134                    if (currentUrl.includes(childHref)) {
135                        childLink.addClass("active"); // Add active class to the matching child link
136                        isActive = true; // Mark that a child is active
137                    } else {
138                        childLink.removeClass("active"); // Ensure other child links are not active
139                    }
140                });
141        
142                // If any child is active, also mark the parent as active
143                if (isActive) {
144                    parentLink.addClass("active");
145                } else {
146                    parentLink.removeClass("active");
147                }
148            });
149        
150            // Handle standalone .nav__link without children (but excluding parents)
151            const standaloneLinks = $(`${navSelector} .nav__link`).not(`${navSelector} .nav__item.parent .nav__link`); // Exclude parent links
152            standaloneLinks.each(function () {
153                const link = $(this);
154                const linkHref = link.attr("href");
155        
156                if (currentUrl.includes(linkHref)) {
157                    link.addClass("active"); // Add active class to the .nav__link
158                } else {
159                    link.removeClass("active"); // Ensure others are not active
160                }
161            });
162        }
163        
164        highlightActiveLink(".main-header");  // For the main-header navigation
165        highlightActiveLink(".page-nav");    // For the page-nav navigation
166        toggleNav();
167        burgerEvent();
168        mobileNavDropdown();
169    };
170
171    Animation.prototype.handle404 = function () {
172        const container = $("section.404");
173        if (!container.length) return;
174
175        let initialWidth = window.innerWidth;
176
177        container.each(function () {
178            const self = $(this);
179            const headingText = self.find("h1").contents();
180
181            window.addEventListener("resize", () => {
182                const currentWidth = window.innerWidth;
183
184                if (currentWidth !== initialWidth) {
185                    initialWidth = currentWidth;
186                    handleResize(self, headingText);
187                }
188            });
189
190            handleResize(self, headingText);
191        });
192
193        function handleResize(parent, headingText) {
194            const heading = parent.find("h1");
195
196            heading.empty();
197            heading.html(headingText);
198
199            const outerWords = new SplitText(heading, {
200                type: "words",
201                wordsClass: "outer-word",
202                reduceWhiteSpace: false,
203            });
204
205            const innerWords = new SplitText(heading, {
206                type: "words",
207                wordsClass: "inner-word",
208                reduceWhiteSpace: false,
209            });
210
211            gsap.to(parent.find(".inner-word"), {
212                ease: Power3.easeOut,
213                y: 0,
214                stagger: {
215                    each: 0.16,
216                },
217                duration: 0.8,
218                overwrite: true,
219                onComplete: () => {
220                    innerWords.revert();
221                    outerWords.revert();
222                }
223            })
224        }
225    }
226
227    app.Animation = Animation;
228
229    app.ready(function () {
230        console.log("Animation ->");
231        Animation.prototype.init();
232    });
233})(window.app);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.