266 lines
5.8 KiB
PHP
266 lines
5.8 KiB
PHP
<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>
|