Implement GSAP Features in 'neler-yapariz-gsap' Template: Introduced a comprehensive set of GSAP animations and sections in the 'neler-yapariz-gsap' template, enhancing the visual dynamics of the page. This update includes new JavaScript and CSS files for various animations, such as flip, inertia, marquee, and scrolltrigger, along with a structured layout for improved user interaction. Additionally, localization support has been integrated for all text elements, ensuring a seamless experience for users across different languages.
This commit is contained in:
@@ -0,0 +1,265 @@
|
||||
<script>
|
||||
{
|
||||
const split = (text, type = "chars") => {
|
||||
// Handle both single elements and arrays of elements
|
||||
const elements = Array.isArray(text) ? text : [text];
|
||||
|
||||
// Set aria labels
|
||||
elements.forEach((element) => {
|
||||
if (element && typeof element.setAttribute === "function") {
|
||||
element.setAttribute("aria-label", element.textContent);
|
||||
}
|
||||
});
|
||||
|
||||
// Split text and set aria-hidden
|
||||
const splits = new SplitText(text, { type });
|
||||
splits[type].forEach((char) => {
|
||||
if (char && typeof char.setAttribute === "function") {
|
||||
char.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
});
|
||||
|
||||
return splits[type];
|
||||
};
|
||||
|
||||
/** -- Setup and Utils */
|
||||
|
||||
let titleSplit,
|
||||
parSplit,
|
||||
layerItems,
|
||||
isIn = false;
|
||||
|
||||
const animateIn = async (delay = 0) => {
|
||||
isIn = true;
|
||||
animateStripesOut();
|
||||
|
||||
gsap.to(parSplit, {
|
||||
autoAlpha: 1,
|
||||
yPercent: 0,
|
||||
duration: 0.8,
|
||||
delay: 0.65,
|
||||
ease: "expo.out",
|
||||
stagger: {
|
||||
each: 0.08,
|
||||
},
|
||||
});
|
||||
|
||||
await gsap.to(titleSplit.flat(), {
|
||||
yPercent: 0,
|
||||
duration: 1.2,
|
||||
delay: delay,
|
||||
ease: "expo.out",
|
||||
stagger: {
|
||||
each: 0.01,
|
||||
from: "end",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const animateOut = async () => {
|
||||
isIn = false;
|
||||
animateStripesIn();
|
||||
|
||||
gsap.to(parSplit, {
|
||||
autoAlpha: 0,
|
||||
yPercent: 100,
|
||||
duration: 0.8,
|
||||
ease: "expo.out",
|
||||
stagger: {
|
||||
each: 0.08,
|
||||
},
|
||||
});
|
||||
|
||||
await gsap.to(titleSplit.flat(), {
|
||||
yPercent: 110,
|
||||
duration: 0.8,
|
||||
ease: "expo.out",
|
||||
delay: 0.1,
|
||||
stagger: {
|
||||
each: 0.01,
|
||||
from: "center",
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/** -- Scribble Animaiton */
|
||||
let isScribbling = false;
|
||||
const SCRIBBLE_CONFIG = {
|
||||
ROTATION_RANGE: 20,
|
||||
TIME_BETWEEN_SCRIBBLES: 0.015,
|
||||
VISIBILITY_DURATION: 0.01,
|
||||
REVERSE_ORDER: true,
|
||||
};
|
||||
|
||||
const animateScribble = (scribble) => {
|
||||
if (isScribbling) return;
|
||||
isScribbling = true;
|
||||
|
||||
gsap.set(scribble, { autoAlpha: 0, rotation: 0 });
|
||||
|
||||
const tl = gsap.timeline();
|
||||
|
||||
const scribblesToAnimate = [...scribble].reverse();
|
||||
|
||||
scribblesToAnimate.forEach((item, index) => {
|
||||
const randomRotation =
|
||||
Math.random() * SCRIBBLE_CONFIG.ROTATION_RANGE -
|
||||
SCRIBBLE_CONFIG.ROTATION_RANGE / 2;
|
||||
const baseDelay = index * SCRIBBLE_CONFIG.TIME_BETWEEN_SCRIBBLES;
|
||||
|
||||
tl.add(
|
||||
gsap.set(item, {
|
||||
autoAlpha: 1,
|
||||
rotation: randomRotation,
|
||||
delay: baseDelay,
|
||||
})
|
||||
);
|
||||
|
||||
tl.add(
|
||||
gsap.set(item, {
|
||||
autoAlpha: 0,
|
||||
delay: baseDelay + SCRIBBLE_CONFIG.VISIBILITY_DURATION,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
tl.call(() => {
|
||||
isScribbling = false;
|
||||
});
|
||||
};
|
||||
|
||||
// hero stripes animation
|
||||
let heroStripes,
|
||||
stripes,
|
||||
stripesAnimation = null;
|
||||
|
||||
const calcX = (i) => {
|
||||
return i % 2 === 0
|
||||
? -heroStripes[i].scrollWidth
|
||||
: heroStripes[i].scrollWidth;
|
||||
};
|
||||
|
||||
const animateStripesIn = () => {
|
||||
if (stripesAnimation) {
|
||||
stripesAnimation.kill();
|
||||
}
|
||||
|
||||
// play video on the hero
|
||||
document.querySelector("video").play()
|
||||
|
||||
gsap.set(heroStripes, {
|
||||
autoAlpha: 1,
|
||||
x: (i) => calcX(i),
|
||||
yPercent: (i) => (heroStripes.length / 2 - i) * 80,
|
||||
});
|
||||
|
||||
gsap.set(stripes, {
|
||||
rotation: (i) => Math.random() * 30,
|
||||
ease: "expo.out",
|
||||
});
|
||||
|
||||
stripesAnimation = gsap.to(heroStripes, {
|
||||
x: 0,
|
||||
delay: 0.2,
|
||||
duration: (i) => Math.random() + 1.2,
|
||||
ease: "expo.out",
|
||||
});
|
||||
};
|
||||
|
||||
const animateStripesOut = () => {
|
||||
if (stripesAnimation) {
|
||||
stripesAnimation.kill();
|
||||
}
|
||||
|
||||
stripesAnimation = gsap.to(heroStripes, {
|
||||
x: (i) => calcX(i),
|
||||
duration: 0.8,
|
||||
ease: "expo.out",
|
||||
});
|
||||
};
|
||||
|
||||
addEventListener("GSAPReady", (event) => {
|
||||
const wrapper = document.querySelector("[data-module='hero']");
|
||||
if (!wrapper) return;
|
||||
|
||||
const layer = wrapper.querySelector("[data-hero='layer']");
|
||||
layerItems = layer.children;
|
||||
const title = wrapper.querySelector("[data-hero='title']");
|
||||
const toggle = wrapper.querySelector("[data-hero='toggle']");
|
||||
const alpha = document.querySelectorAll("[data-hero='alpha']");
|
||||
const par = document.querySelectorAll("[data-hero='par']");
|
||||
const scribble = [
|
||||
...document.querySelector("[data-hero='scribble']").children[0].children,
|
||||
];
|
||||
|
||||
stripes = [...layer.children];
|
||||
heroStripes = stripes.map((item) => item.children[0]);
|
||||
gsap.set(heroStripes, { autoAlpha: 0 });
|
||||
|
||||
gsap.to(layer, {
|
||||
yPercent: 10,
|
||||
scrollTrigger: {
|
||||
trigger: layer,
|
||||
start: "top top",
|
||||
end: "+=100%",
|
||||
scrub: true,
|
||||
},
|
||||
});
|
||||
|
||||
// split
|
||||
titleSplit = split(title.children, "chars");
|
||||
parSplit = split(par, "lines");
|
||||
|
||||
// initial state
|
||||
gsap.set(titleSplit.flat(), { yPercent: -110 });
|
||||
gsap.set(layer, { autoAlpha: 1 });
|
||||
gsap.set(toggle, { scale: 3, rotation: 360 });
|
||||
gsap.set(parSplit, { autoAlpha: 0, yPercent: 100 });
|
||||
gsap.set(alpha, { autoAlpha: 0, scale: 0.7 });
|
||||
gsap.set(scribble, { autoAlpha: 0 });
|
||||
|
||||
animateIn(0.6);
|
||||
|
||||
gsap.to(toggle, {
|
||||
scale: 1,
|
||||
rotation: 0,
|
||||
delay: 0,
|
||||
duration: 1.2,
|
||||
ease: "expo.inOut",
|
||||
});
|
||||
|
||||
gsap.to(parSplit, {
|
||||
autoAlpha: 1,
|
||||
yPercent: 0,
|
||||
duration: 0.8,
|
||||
delay: 0.65,
|
||||
ease: "expo.out",
|
||||
stagger: {
|
||||
each: 0.08,
|
||||
},
|
||||
});
|
||||
|
||||
gsap.to(alpha, {
|
||||
autoAlpha: 1,
|
||||
scale: 1,
|
||||
duration: 0.8,
|
||||
delay: 0.9,
|
||||
ease: "expo.out",
|
||||
});
|
||||
|
||||
toggle.querySelector("input").addEventListener("change", (event) => {
|
||||
if (event.target.checked) {
|
||||
animateOut();
|
||||
} else {
|
||||
animateIn();
|
||||
}
|
||||
});
|
||||
|
||||
toggle.onmouseenter = () => {
|
||||
if (!isIn) return;
|
||||
// console.log("mouseenter");
|
||||
animateScribble(scribble);
|
||||
};
|
||||
});
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user