You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
7.8 KiB
231 lines
7.8 KiB
/** @odoo-module */
|
|
import PublicWidget from "@web/legacy/js/public/public_widget";
|
|
import { registry } from "@web/core/registry";
|
|
|
|
export const NavigationScroll = PublicWidget.Widget.extend({
|
|
selector: "#wrapwrap",
|
|
|
|
start() {
|
|
this._super.apply(this, arguments);
|
|
this._handleNavStyle();
|
|
this._navbar_animation();
|
|
this._setupScrollHandler();
|
|
this._initializeAnimations();
|
|
this._triggerHeroAnimation();
|
|
this._setupPortfolioAnimations();
|
|
},
|
|
|
|
_setupScrollHandler() {
|
|
this._onScroll = this._onScroll.bind(this);
|
|
window.addEventListener('scroll', this._onScroll);
|
|
this._setupIntersectionObserver();
|
|
},
|
|
|
|
_setupIntersectionObserver() {
|
|
const options = {
|
|
root: null,
|
|
rootMargin: '0px',
|
|
threshold: 0.1,
|
|
};
|
|
|
|
this.observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
const target = entry.target;
|
|
this._triggerAnimation(target);
|
|
this.observer.unobserve(target);
|
|
}
|
|
});
|
|
}, options);
|
|
|
|
// Expanded list of animated elements
|
|
const animatedElements = document.querySelectorAll(
|
|
'.anime_video, .anime_video_right, .anime_h, .anime_card, .anime_h2, ' +
|
|
'.anime_card2, .anime_grid2, .testimonial, .location_head, ' +
|
|
'.location_left, .location_right, .anime_section, .anime_grid'
|
|
);
|
|
|
|
animatedElements.forEach(element => {
|
|
this.observer.observe(element);
|
|
});
|
|
},
|
|
|
|
_triggerAnimation(element) {
|
|
// Comprehensive animation method covering all classes
|
|
const animationOptions = {
|
|
duration: 1.5,
|
|
ease: "power2.out"
|
|
};
|
|
|
|
// Left sliding animations (from left)
|
|
if (element.classList.contains('anime_video') ||
|
|
element.classList.contains('anime_h') ||
|
|
element.classList.contains('anime_card') ||
|
|
element.classList.contains('anime_h2') ||
|
|
element.classList.contains('testimonial') ||
|
|
element.classList.contains('location_head') ||
|
|
element.classList.contains('location_left')) {
|
|
gsap.fromTo(element,
|
|
{ x: "-100vw", opacity: 0 },
|
|
{ x: 0, opacity: 1, ...animationOptions }
|
|
);
|
|
}
|
|
|
|
// Right sliding animations (from right)
|
|
else if (element.classList.contains('anime_video_right') ||
|
|
element.classList.contains('anime_card2') ||
|
|
element.classList.contains('anime_grid2') ||
|
|
element.classList.contains('location_right')) {
|
|
gsap.fromTo(element,
|
|
{ x: "200vw", opacity: 0 },
|
|
{ x: 0, opacity: 1, ...animationOptions }
|
|
);
|
|
}
|
|
|
|
// Grid and section animations
|
|
else if (element.classList.contains('anime_grid') ||
|
|
element.classList.contains('anime_section')) {
|
|
gsap.fromTo(element,
|
|
{ y: "50px", opacity: 0 },
|
|
{ y: 0, opacity: 1, duration: 1.5, ease: "power2.out" }
|
|
);
|
|
}
|
|
},
|
|
|
|
_setupPortfolioAnimations() {
|
|
setTimeout(() => {
|
|
// Portfolio header animation
|
|
const portfolioHeader = document.querySelector('.project_head');
|
|
const portfolioTitle = document.querySelector('.project_head h1');
|
|
|
|
if (portfolioHeader && portfolioTitle) {
|
|
// Create a timeline for more complex animations
|
|
const tl = gsap.timeline({ defaults: { duration: 1 } });
|
|
|
|
// Animate background
|
|
tl.fromTo(portfolioHeader,
|
|
{ opacity: 0, y: -50 },
|
|
{ opacity: 1, y: 0, ease: "power2.out" }
|
|
)
|
|
// Animate title
|
|
.fromTo(portfolioTitle,
|
|
{ opacity: 0, scale: 0.5 },
|
|
{ opacity: 1, scale: 1, ease: "back.out(1.7)" },
|
|
0.5 // Slight delay for staggered effect
|
|
);
|
|
}
|
|
}, 100);
|
|
},
|
|
|
|
|
|
_triggerHeroAnimation() {
|
|
setTimeout(() => {
|
|
// Letter span animation
|
|
const letters = document.querySelectorAll(".text span");
|
|
if (letters.length > 0) {
|
|
gsap.to(letters, {
|
|
opacity: 1,
|
|
y: 0,
|
|
duration: 0.5,
|
|
ease: "power2.out",
|
|
stagger: 0.1,
|
|
});
|
|
}
|
|
|
|
// Hero elements animation
|
|
const heroElements = {
|
|
hero: document.querySelector(".hero"),
|
|
hero_title: document.querySelector(".hero__title"),
|
|
hero_subtitle: document.querySelector(".hero__subtitle"),
|
|
};
|
|
|
|
// Verify elements exist before animating
|
|
if (heroElements.hero && heroElements.hero_title && heroElements.hero_subtitle) {
|
|
const tl = gsap.timeline({
|
|
defaults: {
|
|
duration: 1,
|
|
opacity: 0
|
|
}
|
|
});
|
|
|
|
tl.from(heroElements.hero, {
|
|
scale: 2
|
|
})
|
|
.from(heroElements.hero_title, {
|
|
y: -10,
|
|
scale: 0.5
|
|
})
|
|
.from(heroElements.hero_subtitle, {
|
|
y: 10,
|
|
scale: 0.5
|
|
});
|
|
}
|
|
}, 100);
|
|
},
|
|
|
|
destroy() {
|
|
if (this.observer) {
|
|
this.observer.disconnect();
|
|
}
|
|
window.removeEventListener('scroll', this._onScroll);
|
|
this._super.apply(this, arguments);
|
|
},
|
|
|
|
_initializeAnimations() {
|
|
// Ensure GSAP is fully initialized
|
|
if (window.gsap) {
|
|
window.gsap.registerPlugin();
|
|
}
|
|
},
|
|
|
|
_handleNavStyle() {
|
|
const currentPath = window.location.pathname;
|
|
const targetNav = this.$el.find('a.nav-link');
|
|
const logoName = this.$el.find('#theme_name');
|
|
const toggleButton = this.$el.find('.navbar-toggler img');
|
|
|
|
if (currentPath === "/" || currentPath === "/home") {
|
|
if (targetNav.length > 0) {
|
|
targetNav.removeClass('nav-link2');
|
|
logoName.addClass('span1').removeClass('brandD');
|
|
}
|
|
|
|
} else {
|
|
if (targetNav.length > 0) {
|
|
targetNav.addClass('nav-link2');
|
|
logoName.addClass('brandD').removeClass('span1');
|
|
toggleButton.attr('src', '/theme_upshift/static/src/img/icons/black.svg');
|
|
}
|
|
}
|
|
},
|
|
|
|
_navbar_animation() {
|
|
const timeline = gsap.timeline({ defaults: { duration: 1 } });
|
|
timeline
|
|
.from(".navigation", { y: "-100%", duration: 2, ease: "bounce" })
|
|
.from(".nav-link", { opacity: 0, stagger: 0.5 })
|
|
.from(
|
|
".navbar-brand",
|
|
{ x: "-100%", opacity: 0 },
|
|
{ x: "0%", opacity: 1, ease: "power1.in" },
|
|
"<.5"
|
|
);
|
|
},
|
|
|
|
_onScroll() {
|
|
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
|
const currentPath = window.location.pathname;
|
|
|
|
if (scrollTop > 0) {
|
|
if (currentPath === "/" || currentPath === "/home") {
|
|
this.$el.find(".navigation")[0].classList.add("scrolled");
|
|
} else {
|
|
this.$el.find(".navigation")[0].classList.add("scrolled2");
|
|
}
|
|
} else {
|
|
this.$el.find(".navigation")[0].classList.remove("scrolled", "scrolled2");
|
|
}
|
|
},
|
|
});
|
|
|
|
PublicWidget.registry.NavigationScroll = NavigationScroll;
|